selection-post-fixer.js 24 KB

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