selection-post-fixer.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import Model from '../../../src/model/model';
  6. import ModelPosition from '../../../src/model/position';
  7. import ModelRange from '../../../src/model/range';
  8. import { injectSelectionPostFixer } from '../../../src/model/utils/selection-post-fixer';
  9. import { getData as getModelData, setData as setModelData } from '../../../src/dev-utils/model';
  10. describe( 'Selection post-fixer', () => {
  11. describe( 'injectSelectionPostFixer()', () => {
  12. it( 'is a function', () => {
  13. expect( injectSelectionPostFixer ).to.be.a( 'function' );
  14. } );
  15. } );
  16. describe( 'injected behavior', () => {
  17. let model, modelRoot;
  18. beforeEach( () => {
  19. model = new Model();
  20. modelRoot = model.document.createRoot();
  21. model.schema.register( 'paragraph', { inheritAllFrom: '$block' } );
  22. model.schema.register( 'table', {
  23. allowWhere: '$block',
  24. isObject: true,
  25. isLimit: true
  26. } );
  27. model.schema.register( 'tableRow', {
  28. allowIn: 'table',
  29. isLimit: true
  30. } );
  31. model.schema.register( 'tableCell', {
  32. allowIn: 'tableRow',
  33. allowContentOf: '$block',
  34. isLimit: true
  35. } );
  36. model.schema.register( 'image', {
  37. allowIn: '$root',
  38. isObject: true
  39. } );
  40. model.schema.register( 'caption', {
  41. allowIn: 'image',
  42. allowContentOf: '$block',
  43. isLimit: true
  44. } );
  45. } );
  46. it( 'should not crash if there is no correct position for model selection', () => {
  47. setModelData( model, '' );
  48. expect( getModelData( model ) ).to.equal( '[]' );
  49. } );
  50. it( 'should react to structure changes', () => {
  51. setModelData( model, '<paragraph>[]foo</paragraph><image></image>' );
  52. model.change( writer => {
  53. writer.remove( modelRoot.getChild( 0 ) );
  54. } );
  55. expect( getModelData( model ) ).to.equal( '[<image></image>]' );
  56. } );
  57. it( 'should react to selection changes', () => {
  58. setModelData( model, '<paragraph>[]foo</paragraph><image></image>' );
  59. // <paragraph>foo</paragraph>[]<image></image>
  60. model.change( writer => {
  61. writer.setSelection(
  62. ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 1 )
  63. );
  64. } );
  65. expect( getModelData( model ) ).to.equal( '<paragraph>foo[]</paragraph><image></image>' );
  66. } );
  67. describe( 'non-collapsed selection - table scenarios', () => {
  68. beforeEach( () => {
  69. setModelData( model,
  70. '<paragraph>[]foo</paragraph>' +
  71. '<table>' +
  72. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  73. '</table>' +
  74. '<paragraph>bar</paragraph>'
  75. );
  76. } );
  77. it( 'should fix #1', () => {
  78. // <paragraph>f[oo</paragraph><table><tableRow><tableCell></tableCell>]<tableCell>...
  79. model.change( writer => {
  80. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  81. modelRoot.getChild( 0 ), 1,
  82. modelRoot.getChild( 1 ).getChild( 0 ), 1
  83. ) );
  84. } );
  85. expect( getModelData( model ) ).to.equal(
  86. '<paragraph>f[oo</paragraph>' +
  87. '<table>' +
  88. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  89. '</table>]' +
  90. '<paragraph>bar</paragraph>'
  91. );
  92. } );
  93. it( 'should fix #2', () => {
  94. // ...<table><tableRow><tableCell></tableCell>[<tableCell></tableCell></tableRow></table><paragraph>b]ar</paragraph>
  95. model.change( writer => {
  96. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  97. modelRoot.getChild( 1 ).getChild( 0 ), 1,
  98. modelRoot.getChild( 2 ), 1
  99. ) );
  100. } );
  101. expect( getModelData( model ) ).to.equal(
  102. '<paragraph>foo</paragraph>' +
  103. '[<table>' +
  104. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  105. '</table>' +
  106. '<paragraph>b]ar</paragraph>'
  107. );
  108. } );
  109. it( 'should fix #3', () => {
  110. // <paragraph>f[oo</paragraph><table>]<tableRow>...
  111. model.change( writer => {
  112. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  113. modelRoot.getChild( 0 ), 1,
  114. modelRoot.getChild( 1 ), 0
  115. ) );
  116. } );
  117. expect( getModelData( model ) ).to.equal(
  118. '<paragraph>f[oo</paragraph>' +
  119. '<table>' +
  120. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  121. '</table>]' +
  122. '<paragraph>bar</paragraph>'
  123. );
  124. } );
  125. it( 'should fix #4', () => {
  126. // <paragraph>foo</paragraph><table><tableRow><tableCell>a[aa</tableCell><tableCell>b]bb</tableCell>
  127. model.change( writer => {
  128. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  129. modelRoot.getChild( 1 ).getChild( 0 ).getChild( 0 ), 1,
  130. modelRoot.getChild( 1 ).getChild( 0 ).getChild( 1 ), 2
  131. ) );
  132. } );
  133. expect( getModelData( model ) ).to.equal(
  134. '<paragraph>foo</paragraph>' +
  135. '[<table>' +
  136. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  137. '</table>]' +
  138. '<paragraph>bar</paragraph>'
  139. );
  140. } );
  141. it( 'should fix #5', () => {
  142. setModelData( model,
  143. '<paragraph>foo</paragraph>' +
  144. '<table>' +
  145. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  146. '</table>' +
  147. '[]' +
  148. '<table>' +
  149. '<tableRow><tableCell>xxx</tableCell><tableCell>yyy</tableCell></tableRow>' +
  150. '</table>' +
  151. '<paragraph>baz</paragraph>'
  152. );
  153. expect( getModelData( model ) ).to.equal(
  154. '<paragraph>foo</paragraph>' +
  155. '[<table>' +
  156. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  157. '</table>]' +
  158. '<table>' +
  159. '<tableRow><tableCell>xxx</tableCell><tableCell>yyy</tableCell></tableRow>' +
  160. '</table>' +
  161. '<paragraph>baz</paragraph>'
  162. );
  163. } );
  164. // There's a chance that this and the following test will not be up to date with
  165. // how the table feature is really implemented once we'll introduce row/cells/columns selection
  166. // in which case all these elements will need to be marked as objects.
  167. it( 'should fix #6 (element selection of not an object)', () => {
  168. setModelData( model,
  169. '<paragraph>foo</paragraph>' +
  170. '<table>' +
  171. '[<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>]' +
  172. '</table>' +
  173. '<paragraph>baz</paragraph>'
  174. );
  175. expect( getModelData( model ) ).to.equal(
  176. '<paragraph>foo</paragraph>' +
  177. '[<table>' +
  178. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  179. '</table>]' +
  180. '<paragraph>baz</paragraph>'
  181. );
  182. } );
  183. it( 'should fix #7 (element selection of non-objects)', () => {
  184. setModelData( model,
  185. '<paragraph>foo</paragraph>' +
  186. '<table>' +
  187. '[<tableRow><tableCell>1</tableCell><tableCell>2</tableCell></tableRow>' +
  188. '<tableRow><tableCell>3</tableCell><tableCell>4</tableCell>]</tableRow>' +
  189. '<tableRow><tableCell>5</tableCell><tableCell>6</tableCell></tableRow>' +
  190. '</table>' +
  191. '<paragraph>baz</paragraph>'
  192. );
  193. expect( getModelData( model ) ).to.equal(
  194. '<paragraph>foo</paragraph>' +
  195. '[<table>' +
  196. '<tableRow><tableCell>1</tableCell><tableCell>2</tableCell></tableRow>' +
  197. '<tableRow><tableCell>3</tableCell><tableCell>4</tableCell></tableRow>' +
  198. '<tableRow><tableCell>5</tableCell><tableCell>6</tableCell></tableRow>' +
  199. '</table>]' +
  200. '<paragraph>baz</paragraph>'
  201. );
  202. } );
  203. it( 'should fix #8 (cross-limit selection which starts in a non-limit elements)', () => {
  204. model.schema.extend( 'paragraph', { allowIn: 'tableCell' } );
  205. setModelData( model,
  206. '<paragraph>foo</paragraph>' +
  207. '<table>' +
  208. '<tableRow>' +
  209. '<tableCell><paragraph>f[oo</paragraph></tableCell>' +
  210. '<tableCell><paragraph>b]ar</paragraph></tableCell>' +
  211. '</tableRow>' +
  212. '</table>' +
  213. '<paragraph>baz</paragraph>'
  214. );
  215. expect( getModelData( model ) ).to.equal(
  216. '<paragraph>foo</paragraph>' +
  217. '[<table>' +
  218. '<tableRow>' +
  219. '<tableCell><paragraph>foo</paragraph></tableCell>' +
  220. '<tableCell><paragraph>bar</paragraph></tableCell>' +
  221. '</tableRow>' +
  222. '</table>]' +
  223. '<paragraph>baz</paragraph>'
  224. );
  225. } );
  226. it( 'should not fix #1', () => {
  227. setModelData( model,
  228. '<paragraph>foo</paragraph>' +
  229. '<table>' +
  230. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  231. '</table>' +
  232. '<paragraph>b[ar</paragraph>' +
  233. '<paragraph>ba]z</paragraph>'
  234. );
  235. expect( getModelData( model ) ).to.equal(
  236. '<paragraph>foo</paragraph>' +
  237. '<table>' +
  238. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  239. '</table>' +
  240. '<paragraph>b[ar</paragraph>' +
  241. '<paragraph>ba]z</paragraph>'
  242. );
  243. } );
  244. it( 'should fix multiple ranges #1', () => {
  245. model.change( writer => {
  246. const ranges = [
  247. new ModelRange( new ModelPosition( modelRoot, [ 0, 1 ] ), new ModelPosition( modelRoot, [ 1, 0 ] ) ),
  248. new ModelRange( new ModelPosition( modelRoot, [ 1, 0, 0, 0 ] ), new ModelPosition( modelRoot, [ 1, 1 ] ) )
  249. ];
  250. writer.setSelection( ranges );
  251. } );
  252. expect( getModelData( model ) ).to.equal(
  253. '<paragraph>f[oo</paragraph>' +
  254. '<table>' +
  255. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  256. '</table>]' +
  257. '<paragraph>bar</paragraph>'
  258. );
  259. } );
  260. it( 'should fix multiple ranges #2', () => {
  261. model.change( writer => {
  262. const ranges = [
  263. new ModelRange( new ModelPosition( modelRoot, [ 0, 1 ] ), new ModelPosition( modelRoot, [ 1, 0 ] ) ),
  264. new ModelRange( new ModelPosition( modelRoot, [ 1, 0, 0, 0 ] ), new ModelPosition( modelRoot, [ 2, 2 ] ) )
  265. ];
  266. writer.setSelection( ranges );
  267. } );
  268. expect( getModelData( model ) ).to.equal(
  269. '<paragraph>f[oo</paragraph>' +
  270. '<table>' +
  271. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  272. '</table>' +
  273. '<paragraph>ba]r</paragraph>'
  274. );
  275. } );
  276. it( 'should fix multiple ranges #3', () => {
  277. setModelData( model,
  278. '<paragraph>foo</paragraph>' +
  279. '<table>' +
  280. '<tableRow><tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  281. '<tableRow>]<tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  282. '<tableRow>]<tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  283. '<tableRow>]<tableCell>[aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  284. '</table>' +
  285. '<paragraph>b]az</paragraph>'
  286. );
  287. expect( getModelData( model ) ).to.equal(
  288. '<paragraph>foo</paragraph>' +
  289. '[<table>' +
  290. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  291. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  292. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  293. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  294. '</table>' +
  295. '<paragraph>b]az</paragraph>'
  296. );
  297. } );
  298. it( 'should fix multiple ranges #4', () => {
  299. model.change( writer => {
  300. const ranges = [
  301. new ModelRange( new ModelPosition( modelRoot, [ 0, 1 ] ), new ModelPosition( modelRoot, [ 1, 0 ] ) ),
  302. new ModelRange( new ModelPosition( modelRoot, [ 1, 0, 0, 0 ] ), new ModelPosition( modelRoot, [ 2, 1 ] ) ),
  303. new ModelRange( new ModelPosition( modelRoot, [ 2, 2 ] ), new ModelPosition( modelRoot, [ 2, 3 ] ) )
  304. ];
  305. writer.setSelection( ranges );
  306. } );
  307. expect( getModelData( model ) ).to.equal(
  308. '<paragraph>f[oo</paragraph>' +
  309. '<table>' +
  310. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  311. '</table>' +
  312. '<paragraph>b]a[r]</paragraph>'
  313. );
  314. } );
  315. } );
  316. describe( 'non-collapsed selection - image scenarios', () => {
  317. beforeEach( () => {
  318. setModelData( model,
  319. '<paragraph>[]foo</paragraph>' +
  320. '<image>' +
  321. '<caption>xxx</caption>' +
  322. '</image>' +
  323. '<paragraph>bar</paragraph>'
  324. );
  325. } );
  326. it( 'should fix #1 (crossing object and limit boundaries)', () => {
  327. model.change( writer => {
  328. // <paragraph>f[oo</paragraph><image><caption>x]xx</caption>...
  329. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  330. modelRoot.getChild( 0 ), 1,
  331. modelRoot.getChild( 1 ).getChild( 0 ), 1
  332. ) );
  333. } );
  334. expect( getModelData( model ) ).to.equal(
  335. '<paragraph>f[oo</paragraph>' +
  336. '<image>' +
  337. '<caption>xxx</caption>' +
  338. '</image>]' +
  339. '<paragraph>bar</paragraph>'
  340. );
  341. } );
  342. it( 'should fix #2 (crossing object boundary)', () => {
  343. model.change( writer => {
  344. // <paragraph>f[oo</paragraph><image>]<caption>xxx</caption>...
  345. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  346. modelRoot.getChild( 0 ), 1,
  347. modelRoot.getChild( 1 ), 0
  348. ) );
  349. } );
  350. expect( getModelData( model ) ).to.equal(
  351. '<paragraph>f[oo</paragraph>' +
  352. '<image>' +
  353. '<caption>xxx</caption>' +
  354. '</image>]' +
  355. '<paragraph>bar</paragraph>'
  356. );
  357. } );
  358. it( 'should fix #3 (crossing object boundary)', () => {
  359. model.change( writer => {
  360. // <paragraph>f[oo</paragraph><image><caption>xxx</caption>]</image>...
  361. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  362. modelRoot.getChild( 0 ), 1,
  363. modelRoot.getChild( 1 ), 1
  364. ) );
  365. } );
  366. expect( getModelData( model ) ).to.equal(
  367. '<paragraph>f[oo</paragraph>' +
  368. '<image>' +
  369. '<caption>xxx</caption>' +
  370. '</image>]' +
  371. '<paragraph>bar</paragraph>'
  372. );
  373. } );
  374. it( 'should fix #4 (element selection of not an object)', () => {
  375. model.change( writer => {
  376. // <paragraph>foo</paragraph><image>[<caption>xxx</caption>]</image>...
  377. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  378. modelRoot.getChild( 1 ), 0,
  379. modelRoot.getChild( 1 ), 1
  380. ) );
  381. } );
  382. expect( getModelData( model ) ).to.equal(
  383. '<paragraph>foo</paragraph>' +
  384. '[<image>' +
  385. '<caption>xxx</caption>' +
  386. '</image>]' +
  387. '<paragraph>bar</paragraph>'
  388. );
  389. } );
  390. it( 'should not fix #1 (element selection of an object)', () => {
  391. model.change( writer => {
  392. // <paragraph>foo</paragraph>[<image><caption>xxx</caption></image>]...
  393. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  394. modelRoot, 1,
  395. modelRoot, 2
  396. ) );
  397. } );
  398. expect( getModelData( model ) ).to.equal(
  399. '<paragraph>foo</paragraph>' +
  400. '[<image>' +
  401. '<caption>xxx</caption>' +
  402. '</image>]' +
  403. '<paragraph>bar</paragraph>'
  404. );
  405. } );
  406. it( 'should not fix #2 (inside a limit)', () => {
  407. model.change( writer => {
  408. const caption = modelRoot.getChild( 1 ).getChild( 0 );
  409. // <paragraph>foo</paragraph><image><caption>[xxx]</caption></image>...
  410. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  411. caption, 0,
  412. caption, 3
  413. ) );
  414. } );
  415. expect( getModelData( model ) ).to.equal(
  416. '<paragraph>foo</paragraph>' +
  417. '<image>' +
  418. '<caption>[xxx]</caption>' +
  419. '</image>' +
  420. '<paragraph>bar</paragraph>'
  421. );
  422. } );
  423. it( 'should not fix #3 (inside a limit - partial text selection)', () => {
  424. model.change( writer => {
  425. const caption = modelRoot.getChild( 1 ).getChild( 0 );
  426. // <paragraph>foo</paragraph><image><caption>[xx]x</caption></image>...
  427. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  428. caption, 0,
  429. caption, 2
  430. ) );
  431. } );
  432. expect( getModelData( model ) ).to.equal(
  433. '<paragraph>foo</paragraph>' +
  434. '<image>' +
  435. '<caption>[xx]x</caption>' +
  436. '</image>' +
  437. '<paragraph>bar</paragraph>'
  438. );
  439. } );
  440. it( 'should not fix #4 (inside a limit - partial text selection)', () => {
  441. model.change( writer => {
  442. const caption = modelRoot.getChild( 1 ).getChild( 0 );
  443. // <paragraph>foo</paragraph><image><caption>x[xx]</caption></image>...
  444. writer.setSelection( ModelRange.createFromParentsAndOffsets(
  445. caption, 1,
  446. caption, 3
  447. ) );
  448. } );
  449. expect( getModelData( model ) ).to.equal(
  450. '<paragraph>foo</paragraph>' +
  451. '<image>' +
  452. '<caption>x[xx]</caption>' +
  453. '</image>' +
  454. '<paragraph>bar</paragraph>'
  455. );
  456. } );
  457. } );
  458. describe( 'non-collapsed selection - other scenarios', () => {
  459. it( 'should fix #1 (element selection of not an object)', () => {
  460. setModelData( model,
  461. '<paragraph>aaa</paragraph>' +
  462. '[<paragraph>bbb</paragraph>]' +
  463. '<paragraph>ccc</paragraph>'
  464. );
  465. expect( getModelData( model ) ).to.equal(
  466. '<paragraph>aaa</paragraph>' +
  467. '<paragraph>[bbb]</paragraph>' +
  468. '<paragraph>ccc</paragraph>'
  469. );
  470. } );
  471. it( 'should fix #2 (elements selection of not an object)', () => {
  472. setModelData( model,
  473. '<paragraph>aaa</paragraph>' +
  474. '[<paragraph>bbb</paragraph>' +
  475. '<paragraph>ccc</paragraph>]'
  476. );
  477. expect( getModelData( model ) ).to.equal(
  478. '<paragraph>aaa</paragraph>' +
  479. '<paragraph>[bbb</paragraph>' +
  480. '<paragraph>ccc]</paragraph>'
  481. );
  482. } );
  483. it( 'should fix #3 (selection must not cross a limit element; starts in a root)', () => {
  484. model.schema.register( 'a', { isLimit: true, allowIn: '$root' } );
  485. model.schema.register( 'b', { isLimit: true, allowIn: 'a' } );
  486. model.schema.register( 'c', { allowIn: 'b' } );
  487. model.schema.extend( '$text', { allowIn: 'c' } );
  488. setModelData( model,
  489. '<a><b><c>[</c></b></a>]'
  490. );
  491. expect( getModelData( model ) ).to.equal( '[<a><b><c></c></b></a>]' );
  492. } );
  493. it( 'should fix #5 (selection must not cross a limit element; ends in a root)', () => {
  494. model.schema.register( 'a', { isLimit: true, allowIn: '$root' } );
  495. model.schema.register( 'b', { isLimit: true, allowIn: 'a' } );
  496. model.schema.register( 'c', { allowIn: 'b' } );
  497. model.schema.extend( '$text', { allowIn: 'c' } );
  498. setModelData( model,
  499. '[<a><b><c>]</c></b></a>'
  500. );
  501. expect( getModelData( model ) ).to.equal( '[<a><b><c></c></b></a>]' );
  502. } );
  503. it( 'should fix #4 (selection must not cross a limit element; starts in a non-limit)', () => {
  504. model.schema.register( 'div', { allowIn: '$root' } );
  505. model.schema.register( 'a', { isLimit: true, allowIn: 'div' } );
  506. model.schema.register( 'b', { isLimit: true, allowIn: 'a' } );
  507. model.schema.register( 'c', { allowIn: 'b' } );
  508. model.schema.extend( '$text', { allowIn: 'c' } );
  509. setModelData( model,
  510. '<div>[<a><b><c>]</c></b></a></div>'
  511. );
  512. expect( getModelData( model ) ).to.equal( '<div>[<a><b><c></c></b></a>]</div>' );
  513. } );
  514. it( 'should fix #6 (selection must not cross a limit element; ends in a non-limit)', () => {
  515. model.schema.register( 'div', { allowIn: '$root' } );
  516. model.schema.register( 'a', { isLimit: true, allowIn: 'div' } );
  517. model.schema.register( 'b', { isLimit: true, allowIn: 'a' } );
  518. model.schema.register( 'c', { allowIn: 'b' } );
  519. model.schema.extend( '$text', { allowIn: 'c' } );
  520. setModelData( model,
  521. '<div><a><b><c>[</c></b></a>]</div>'
  522. );
  523. expect( getModelData( model ) ).to.equal( '<div>[<a><b><c></c></b></a>]</div>' );
  524. } );
  525. it( 'should not fix #7 (selection on text node)', () => {
  526. setModelData( model, '<paragraph>foob[a]r</paragraph>', { lastRangeBackward: true } );
  527. expect( getModelData( model ) ).to.equal( '<paragraph>foob[a]r</paragraph>' );
  528. } );
  529. } );
  530. describe( 'collapsed selection', () => {
  531. beforeEach( () => {
  532. setModelData( model,
  533. '<paragraph>[]foo</paragraph>' +
  534. '<table>' +
  535. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  536. '</table>' +
  537. '<paragraph>bar</paragraph>'
  538. );
  539. } );
  540. it( 'should fix #1', () => {
  541. // <table>[]<tableRow>...
  542. model.change( writer => {
  543. writer.setSelection(
  544. ModelRange.createFromParentsAndOffsets( modelRoot.getChild( 1 ), 0, modelRoot.getChild( 1 ), 0 )
  545. );
  546. } );
  547. expect( getModelData( model ) ).to.equal(
  548. '<paragraph>foo[]</paragraph>' +
  549. '<table>' +
  550. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  551. '</table>' +
  552. '<paragraph>bar</paragraph>'
  553. );
  554. } );
  555. it( 'should fix #2', () => {
  556. // <table><tableRow>[]<tableCell>...
  557. model.change( writer => {
  558. const row = modelRoot.getChild( 1 ).getChild( 0 );
  559. writer.setSelection(
  560. ModelRange.createFromParentsAndOffsets( row, 0, row, 0 )
  561. );
  562. } );
  563. expect( getModelData( model ) ).to.equal(
  564. '<paragraph>foo</paragraph>' +
  565. '<table>' +
  566. '<tableRow><tableCell>[]aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  567. '</table>' +
  568. '<paragraph>bar</paragraph>'
  569. );
  570. } );
  571. it( 'should fix multiple ranges #1', () => {
  572. // []<paragraph></paragraph>[]<table>...
  573. model.change( writer => {
  574. writer.setSelection(
  575. [
  576. ModelRange.createFromParentsAndOffsets( modelRoot, 0, modelRoot, 0 ),
  577. ModelRange.createFromParentsAndOffsets( modelRoot, 1, modelRoot, 1 )
  578. ]
  579. );
  580. } );
  581. expect( getModelData( model ) ).to.equal(
  582. '<paragraph>[]foo[]</paragraph>' +
  583. '<table>' +
  584. '<tableRow><tableCell>aaa</tableCell><tableCell>bbb</tableCell></tableRow>' +
  585. '</table>' +
  586. '<paragraph>bar</paragraph>'
  587. );
  588. } );
  589. } );
  590. } );
  591. } );