selection-post-fixer.js 23 KB

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