insertcontent.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import Document from '../../src/model/document';
  6. import DataController from '../../src/controller/datacontroller';
  7. import insertContent from '../../src/controller/insertcontent';
  8. import DocumentFragment from '../../src/model/documentfragment';
  9. import Text from '../../src/model/text';
  10. import { setData, getData, parse } from '../../src/dev-utils/model';
  11. describe( 'DataController', () => {
  12. let doc, dataController;
  13. describe( 'insertContent', () => {
  14. it( 'uses the passed batch', () => {
  15. const doc = new Document();
  16. doc.createRoot();
  17. doc.schema.allow( { name: '$text', inside: '$root' } );
  18. const dataController = new DataController( doc );
  19. const batch = doc.batch();
  20. setData( doc, 'x[]x' );
  21. insertContent( dataController, new DocumentFragment( [ new Text( 'a' ) ] ), doc.selection, batch );
  22. expect( batch.deltas.length ).to.be.above( 0 );
  23. } );
  24. it( 'accepts DocumentFragment', () => {
  25. const doc = new Document();
  26. const dataController = new DataController( doc );
  27. const batch = doc.batch();
  28. doc.createRoot();
  29. doc.schema.allow( { name: '$text', inside: '$root' } );
  30. setData( doc, 'x[]x' );
  31. insertContent( dataController, new DocumentFragment( [ new Text( 'a' ) ] ), doc.selection, batch );
  32. expect( getData( doc ) ).to.equal( 'xa[]x' );
  33. } );
  34. it( 'accepts Text', () => {
  35. const doc = new Document();
  36. const dataController = new DataController( doc );
  37. const batch = doc.batch();
  38. doc.createRoot();
  39. doc.schema.allow( { name: '$text', inside: '$root' } );
  40. setData( doc, 'x[]x' );
  41. insertContent( dataController, new Text( 'a' ), doc.selection, batch );
  42. expect( getData( doc ) ).to.equal( 'xa[]x' );
  43. } );
  44. describe( 'saves the reference to the original object', () => {
  45. it( 'inline-widget', () => {
  46. doc = new Document();
  47. doc.createRoot();
  48. doc.schema.registerItem( 'paragraph', '$block' );
  49. doc.schema.registerItem( 'inlineWidget' );
  50. doc.schema.allow( { name: 'inlineWidget', inside: '$block' } );
  51. doc.schema.allow( { name: 'inlineWidget', inside: '$clipboardHolder' } );
  52. doc.schema.objects.add( 'inlineWidget' );
  53. dataController = new DataController( doc );
  54. const batch = doc.batch();
  55. setData( doc, '<paragraph>f[]oo</paragraph>' );
  56. const content = parse( '<inlineWidget></inlineWidget>', doc.schema, {
  57. context: [ '$clipboardHolder' ]
  58. } );
  59. insertContent( dataController, content, doc.selection, batch );
  60. expect( doc.getRoot().getChild( 0 ).getChild( 1 ) ).to.equal( content );
  61. } );
  62. it( 'image', () => {
  63. doc = new Document();
  64. doc.createRoot();
  65. doc.schema.registerItem( 'paragraph', '$block' );
  66. doc.schema.registerItem( 'image', '$inline' );
  67. doc.schema.allow( { name: 'image', inside: '$clipboardHolder' } );
  68. doc.schema.objects.add( 'image' );
  69. dataController = new DataController( doc );
  70. const batch = doc.batch();
  71. setData( doc, '<paragraph>foo[]</paragraph>' );
  72. const content = parse( '<image></image>', doc.schema, {
  73. context: [ '$clipboardHolder' ]
  74. } );
  75. insertContent( dataController, content, doc.selection, batch );
  76. expect( doc.getRoot().getChild( 0 ).getChild( 1 ) ).to.equal( content );
  77. } );
  78. } );
  79. describe( 'in simple scenarios', () => {
  80. beforeEach( () => {
  81. doc = new Document();
  82. doc.createRoot();
  83. dataController = new DataController( doc );
  84. const schema = doc.schema;
  85. schema.registerItem( 'image', '$inline' );
  86. schema.registerItem( 'disallowedElement' );
  87. schema.allow( { name: '$text', inside: '$root' } );
  88. schema.allow( { name: 'image', inside: '$root' } );
  89. // Otherwise it won't be passed to the temporary model fragment used inside insert().
  90. schema.allow( { name: 'disallowedElement', inside: '$clipboardHolder' } );
  91. doc.schema.allow( { name: '$text', inside: 'disallowedElement' } );
  92. schema.allow( { name: '$inline', attributes: [ 'bold' ] } );
  93. schema.allow( { name: '$inline', attributes: [ 'italic' ] } );
  94. schema.objects.add( 'image' );
  95. } );
  96. it( 'inserts one text node', () => {
  97. setData( doc, 'f[]oo' );
  98. insertHelper( 'xyz' );
  99. expect( getData( doc ) ).to.equal( 'fxyz[]oo' );
  100. } );
  101. it( 'inserts one text node (at the end)', () => {
  102. setData( doc, 'foo[]' );
  103. insertHelper( 'xyz' );
  104. expect( getData( doc ) ).to.equal( 'fooxyz[]' );
  105. } );
  106. it( 'inserts one text node with attribute', () => {
  107. setData( doc, 'f[]oo' );
  108. insertHelper( '<$text bold="true">xyz</$text>' );
  109. expect( getData( doc ) ).to.equal( 'f<$text bold="true">xyz[]</$text>oo' );
  110. expect( doc.selection.getAttribute( 'bold' ) ).to.be.true;
  111. } );
  112. it( 'inserts one text node with attribute into text with a different attribute', () => {
  113. setData( doc, '<$text bold="true">f[]oo</$text>' );
  114. insertHelper( '<$text italic="true">xyz</$text>' );
  115. expect( getData( doc ) )
  116. .to.equal( '<$text bold="true">f</$text><$text italic="true">xyz[]</$text><$text bold="true">oo</$text>' );
  117. expect( doc.selection.getAttribute( 'italic' ) ).to.be.true;
  118. expect( doc.selection.hasAttribute( 'bold' ) ).to.be.false;
  119. } );
  120. it( 'inserts one text node with attribute into text with the same attribute', () => {
  121. setData( doc, '<$text bold="true">f[]oo</$text>' );
  122. insertHelper( '<$text bold="true">xyz</$text>' );
  123. expect( getData( doc ) )
  124. .to.equal( '<$text bold="true">fxyz[]oo</$text>' );
  125. expect( doc.selection.getAttribute( 'bold' ) ).to.be.true;
  126. } );
  127. it( 'inserts a text without attributes into a text with an attribute', () => {
  128. setData( doc, '<$text bold="true">f[]oo</$text>' );
  129. insertHelper( 'xyz' );
  130. expect( getData( doc ) ).to.equal( '<$text bold="true">f</$text>xyz[]<$text bold="true">oo</$text>' );
  131. expect( doc.selection.hasAttribute( 'bold' ) ).to.be.false;
  132. } );
  133. it( 'inserts an element', () => {
  134. setData( doc, 'f[]oo' );
  135. insertHelper( '<image></image>' );
  136. expect( getData( doc ) ).to.equal( 'f<image></image>[]oo' );
  137. } );
  138. it( 'inserts a text and an element', () => {
  139. setData( doc, 'f[]oo' );
  140. insertHelper( 'xyz<image></image>' );
  141. expect( getData( doc ) ).to.equal( 'fxyz<image></image>[]oo' );
  142. } );
  143. it( 'strips a disallowed element', () => {
  144. setData( doc, 'f[]oo' );
  145. insertHelper( '<disallowedElement>xyz</disallowedElement>' );
  146. expect( getData( doc ) ).to.equal( 'fxyz[]oo' );
  147. } );
  148. it( 'deletes selection before inserting the content', () => {
  149. setData( doc, 'f[abc]oo' );
  150. insertHelper( 'x' );
  151. expect( getData( doc ) ).to.equal( 'fx[]oo' );
  152. } );
  153. describe( 'spaces handling', () => {
  154. // Note: spaces in the view are not encoded like in the DOM, so subsequent spaces must be
  155. // inserted into the model as is. The conversion to nbsps happen on view<=>DOM conversion.
  156. it( 'inserts one space', () => {
  157. setData( doc, 'f[]oo' );
  158. insertHelper( new Text( ' ' ) );
  159. expect( getData( doc ) ).to.equal( 'f []oo' );
  160. } );
  161. it( 'inserts three spaces', () => {
  162. setData( doc, 'f[]oo' );
  163. insertHelper( new Text( ' ' ) );
  164. expect( getData( doc ) ).to.equal( 'f []oo' );
  165. } );
  166. it( 'inserts spaces at the end', () => {
  167. setData( doc, 'foo[]' );
  168. insertHelper( new Text( ' ' ) );
  169. expect( getData( doc ) ).to.equal( 'foo []' );
  170. } );
  171. it( 'inserts one nbsp', () => {
  172. setData( doc, 'f[]oo' );
  173. insertHelper( new Text( '\u200a' ) );
  174. expect( getData( doc ) ).to.equal( 'f\u200a[]oo' );
  175. } );
  176. it( 'inserts word surrounded by spaces', () => {
  177. setData( doc, 'f[]oo' );
  178. insertHelper( new Text( ' xyz ' ) );
  179. expect( getData( doc ) ).to.equal( 'f xyz []oo' );
  180. } );
  181. } );
  182. } );
  183. describe( 'in blocks', () => {
  184. beforeEach( () => {
  185. doc = new Document();
  186. doc.createRoot();
  187. dataController = new DataController( doc );
  188. const schema = doc.schema;
  189. schema.registerItem( 'paragraph', '$block' );
  190. schema.registerItem( 'heading1', '$block' );
  191. schema.registerItem( 'heading2', '$block' );
  192. schema.registerItem( 'blockWidget' );
  193. schema.registerItem( 'inlineWidget' );
  194. schema.registerItem( 'listItem', '$block' );
  195. schema.allow( { name: 'blockWidget', inside: '$root' } );
  196. schema.allow( { name: 'inlineWidget', inside: '$block' } );
  197. schema.allow( { name: 'inlineWidget', inside: '$clipboardHolder' } );
  198. schema.allow( {
  199. name: 'listItem',
  200. inside: '$root',
  201. attributes: [ 'type', 'indent' ]
  202. } );
  203. schema.requireAttributes( 'listItem', [ 'type', 'indent' ] );
  204. schema.objects.add( 'blockWidget' );
  205. schema.objects.add( 'inlineWidget' );
  206. } );
  207. it( 'inserts one text node', () => {
  208. setData( doc, '<paragraph>f[]oo</paragraph>' );
  209. insertHelper( 'xyz' );
  210. expect( getData( doc ) ).to.equal( '<paragraph>fxyz[]oo</paragraph>' );
  211. } );
  212. it( 'inserts one text node to fully selected paragraph', () => {
  213. setData( doc, '<paragraph>[foo]</paragraph>' );
  214. insertHelper( 'xyz' );
  215. expect( getData( doc ) ).to.equal( '<paragraph>xyz[]</paragraph>' );
  216. } );
  217. it( 'inserts one text node to fully selected paragraphs (from outside)', () => {
  218. setData( doc, '[<paragraph>foo</paragraph><paragraph>bar</paragraph>]' );
  219. insertHelper( 'xyz' );
  220. expect( getData( doc ) ).to.equal( '<paragraph>xyz[]</paragraph>' );
  221. } );
  222. it( 'merges two blocks before inserting content (p+p)', () => {
  223. setData( doc, '<paragraph>fo[o</paragraph><paragraph>b]ar</paragraph>' );
  224. insertHelper( 'xyz' );
  225. expect( getData( doc ) ).to.equal( '<paragraph>foxyz[]ar</paragraph>' );
  226. } );
  227. it( 'inserts inline widget and text', () => {
  228. setData( doc, '<paragraph>f[]oo</paragraph>' );
  229. insertHelper( 'xyz<inlineWidget></inlineWidget>' );
  230. expect( getData( doc ) ).to.equal( '<paragraph>fxyz<inlineWidget></inlineWidget>[]oo</paragraph>' );
  231. } );
  232. // Note: In CKEditor 4 the blocks are not merged, but to KISS we're merging here
  233. // because that's what deleteContent() does.
  234. it( 'merges two blocks before inserting content (h+p)', () => {
  235. setData( doc, '<heading1>fo[o</heading1><paragraph>b]ar</paragraph>' );
  236. insertHelper( 'xyz' );
  237. expect( getData( doc ) ).to.equal( '<heading1>foxyz[]ar</heading1>' );
  238. } );
  239. describe( 'block to block handling', () => {
  240. it( 'inserts one paragraph', () => {
  241. setData( doc, '<paragraph>f[]oo</paragraph>' );
  242. insertHelper( '<paragraph>xyz</paragraph>' );
  243. expect( getData( doc ) ).to.equal( '<paragraph>fxyz[]oo</paragraph>' );
  244. } );
  245. it( 'inserts one paragraph (at the end)', () => {
  246. setData( doc, '<paragraph>foo[]</paragraph>' );
  247. insertHelper( '<paragraph>xyz</paragraph>' );
  248. expect( getData( doc ) ).to.equal( '<paragraph>fooxyz[]</paragraph>' );
  249. } );
  250. it( 'inserts one paragraph into an empty paragraph', () => {
  251. setData( doc, '<paragraph>[]</paragraph>' );
  252. insertHelper( '<paragraph>xyz</paragraph>' );
  253. expect( getData( doc ) ).to.equal( '<paragraph>xyz[]</paragraph>' );
  254. } );
  255. it( 'inserts one block into a fully selected content', () => {
  256. setData( doc, '<heading1>[foo</heading1><paragraph>bar]</paragraph>' );
  257. insertHelper( '<heading2>xyz</heading2>' );
  258. expect( getData( doc ) ).to.equal( '<heading2>xyz[]</heading2>' );
  259. } );
  260. it( 'inserts one heading', () => {
  261. setData( doc, '<paragraph>f[]oo</paragraph>' );
  262. insertHelper( '<heading1>xyz</heading1>' );
  263. expect( getData( doc ) ).to.equal( '<paragraph>fxyz[]oo</paragraph>' );
  264. } );
  265. it( 'inserts two headings', () => {
  266. setData( doc, '<paragraph>f[]oo</paragraph>' );
  267. insertHelper( '<heading1>xxx</heading1><heading1>yyy</heading1>' );
  268. expect( getData( doc ) ).to.equal( '<paragraph>fxxx</paragraph><heading1>yyy[]oo</heading1>' );
  269. } );
  270. it( 'inserts one object', () => {
  271. setData( doc, '<paragraph>f[]oo</paragraph>' );
  272. insertHelper( '<blockWidget></blockWidget>' );
  273. expect( getData( doc ) ).to.equal( '<paragraph>f</paragraph>[<blockWidget></blockWidget>]<paragraph>oo</paragraph>' );
  274. } );
  275. it( 'inserts one object (at the end)', () => {
  276. setData( doc, '<paragraph>foo[]</paragraph>' );
  277. insertHelper( '<blockWidget></blockWidget>' );
  278. expect( getData( doc ) ).to.equal( '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]' );
  279. } );
  280. it( 'inserts one object (at the beginning)', () => {
  281. setData( doc, '<paragraph>[]bar</paragraph>' );
  282. insertHelper( '<blockWidget></blockWidget>' );
  283. expect( getData( doc ) ).to.equal( '[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  284. } );
  285. it( 'inserts one list item', () => {
  286. setData( doc, '<paragraph>f[]oo</paragraph>' );
  287. insertHelper( '<listItem indent="0" type="bulleted">xyz</listItem>' );
  288. expect( getData( doc ) ).to.equal( '<paragraph>fxyz[]oo</paragraph>' );
  289. } );
  290. it( 'inserts list item to empty element', () => {
  291. setData( doc, '<paragraph>[]</paragraph>' );
  292. insertHelper( '<listItem indent="0" type="bulleted">xyz</listItem>' );
  293. expect( getData( doc ) ).to.equal( '<listItem indent="0" type="bulleted">xyz[]</listItem>' );
  294. } );
  295. it( 'inserts three list items at the end of paragraph', () => {
  296. setData( doc, '<paragraph>foo[]</paragraph>' );
  297. insertHelper(
  298. '<listItem indent="0" type="bulleted">xxx</listItem>' +
  299. '<listItem indent="0" type="bulleted">yyy</listItem>' +
  300. '<listItem indent="0" type="bulleted">zzz</listItem>'
  301. );
  302. expect( getData( doc ) ).to.equal(
  303. '<paragraph>fooxxx</paragraph>' +
  304. '<listItem indent="0" type="bulleted">yyy</listItem>' +
  305. '<listItem indent="0" type="bulleted">zzz[]</listItem>'
  306. );
  307. } );
  308. it( 'inserts two list items to an empty paragraph', () => {
  309. setData( doc, '<paragraph>a</paragraph><paragraph>[]</paragraph><paragraph>b</paragraph>' );
  310. insertHelper(
  311. '<listItem indent="0" type="bulleted">xxx</listItem>' +
  312. '<listItem indent="0" type="bulleted">yyy</listItem>'
  313. );
  314. expect( getData( doc ) ).to.equal(
  315. '<paragraph>a</paragraph>' +
  316. '<listItem indent="0" type="bulleted">xxx</listItem>' +
  317. '<listItem indent="0" type="bulleted">yyy[]</listItem>' +
  318. '<paragraph>b</paragraph>'
  319. );
  320. } );
  321. } );
  322. describe( 'mixed content to block', () => {
  323. it( 'inserts text + paragraph', () => {
  324. setData( doc, '<paragraph>f[]oo</paragraph>' );
  325. insertHelper( 'xxx<paragraph>yyy</paragraph>' );
  326. expect( getData( doc ) ).to.equal( '<paragraph>fxxx</paragraph><paragraph>yyy[]oo</paragraph>' );
  327. } );
  328. it( 'inserts text + inlineWidget + text + paragraph', () => {
  329. setData( doc, '<paragraph>f[]oo</paragraph>' );
  330. insertHelper( 'xxx<inlineWidget></inlineWidget>yyy<paragraph>zzz</paragraph>' );
  331. expect( getData( doc ) ).to.equal( '<paragraph>fxxx<inlineWidget></inlineWidget>yyy</paragraph><paragraph>zzz[]oo</paragraph>' );
  332. } );
  333. it( 'inserts text + paragraph (at the beginning)', () => {
  334. setData( doc, '<paragraph>[]foo</paragraph>' );
  335. insertHelper( 'xxx<paragraph>yyy</paragraph>' );
  336. expect( getData( doc ) ).to.equal( '<paragraph>xxx</paragraph><paragraph>yyy[]foo</paragraph>' );
  337. } );
  338. it( 'inserts text + paragraph (at the end)', () => {
  339. setData( doc, '<paragraph>foo[]</paragraph>' );
  340. insertHelper( 'xxx<paragraph>yyy</paragraph>' );
  341. expect( getData( doc ) ).to.equal( '<paragraph>fooxxx</paragraph><paragraph>yyy[]</paragraph>' );
  342. } );
  343. it( 'inserts paragraph + text', () => {
  344. setData( doc, '<paragraph>f[]oo</paragraph>' );
  345. insertHelper( '<paragraph>yyy</paragraph>xxx' );
  346. expect( getData( doc ) ).to.equal( '<paragraph>fyyy</paragraph><paragraph>xxx[]oo</paragraph>' );
  347. } );
  348. // This is the expected result, but it was so hard to achieve at this stage that I
  349. // decided to go with the what the next test represents.
  350. // it( 'inserts paragraph + text + inlineWidget + text', () => {
  351. // setData( doc, '<paragraph>f[]oo</paragraph>' );
  352. // insertHelper( '<paragraph>yyy</paragraph>xxx<inlineWidget></inlineWidget>zzz' );
  353. // expect( getData( doc ) )
  354. // .to.equal( '<paragraph>fyyy</paragraph><paragraph>xxx<inlineWidget></inlineWidget>zzz[]oo</paragraph>' );
  355. // } );
  356. // See the comment above.
  357. it( 'inserts paragraph + text + inlineWidget + text', () => {
  358. setData( doc, '<paragraph>f[]oo</paragraph>' );
  359. insertHelper( '<paragraph>yyy</paragraph>xxx<inlineWidget></inlineWidget>zzz' );
  360. expect( getData( doc ) ).to.equal(
  361. '<paragraph>fyyy</paragraph><paragraph>xxx</paragraph>' +
  362. '<paragraph><inlineWidget></inlineWidget></paragraph>' +
  363. '<paragraph>zzz[]oo</paragraph>'
  364. );
  365. } );
  366. it( 'inserts paragraph + text + paragraph', () => {
  367. setData( doc, '<paragraph>f[]oo</paragraph>' );
  368. insertHelper( '<paragraph>yyy</paragraph>xxx<paragraph>zzz</paragraph>' );
  369. expect( getData( doc ) ).to.equal( '<paragraph>fyyy</paragraph><paragraph>xxx</paragraph><paragraph>zzz[]oo</paragraph>' );
  370. } );
  371. it( 'inserts paragraph + text (at the beginning)', () => {
  372. setData( doc, '<paragraph>[]foo</paragraph>' );
  373. insertHelper( '<paragraph>yyy</paragraph>xxx' );
  374. expect( getData( doc ) ).to.equal( '<paragraph>yyy</paragraph><paragraph>xxx[]foo</paragraph>' );
  375. } );
  376. it( 'inserts paragraph + text (at the end)', () => {
  377. setData( doc, '<paragraph>foo[]</paragraph>' );
  378. insertHelper( '<paragraph>yyy</paragraph>xxx' );
  379. expect( getData( doc ) ).to.equal( '<paragraph>fooyyy</paragraph><paragraph>xxx[]</paragraph>' );
  380. } );
  381. it( 'inserts text + heading', () => {
  382. setData( doc, '<paragraph>f[]oo</paragraph>' );
  383. insertHelper( 'xxx<heading1>yyy</heading1>' );
  384. expect( getData( doc ) ).to.equal( '<paragraph>fxxx</paragraph><heading1>yyy[]oo</heading1>' );
  385. } );
  386. it( 'inserts paragraph + object', () => {
  387. setData( doc, '<paragraph>f[]oo</paragraph>' );
  388. insertHelper( '<paragraph>xxx</paragraph><blockWidget></blockWidget>' );
  389. expect( getData( doc ) ).to.equal( '<paragraph>fxxx</paragraph>[<blockWidget></blockWidget>]<paragraph>oo</paragraph>' );
  390. } );
  391. it( 'inserts object + paragraph', () => {
  392. setData( doc, '<paragraph>f[]oo</paragraph>' );
  393. insertHelper( '<blockWidget></blockWidget><paragraph>xxx</paragraph>' );
  394. expect( getData( doc ) ).to.equal( '<paragraph>f</paragraph><blockWidget></blockWidget><paragraph>xxx[]oo</paragraph>' );
  395. } );
  396. } );
  397. describe( 'content over a block object', () => {
  398. it( 'inserts text', () => {
  399. setData( doc, '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  400. insertHelper( 'xxx' );
  401. expect( getData( doc ) ).to.equal( '<paragraph>foo</paragraph><paragraph>xxx[]</paragraph><paragraph>bar</paragraph>' );
  402. } );
  403. it( 'inserts paragraph', () => {
  404. setData( doc, '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  405. insertHelper( '<paragraph>xxx</paragraph>' );
  406. expect( getData( doc ) ).to.equal( '<paragraph>foo</paragraph><paragraph>xxx[]</paragraph><paragraph>bar</paragraph>' );
  407. } );
  408. it( 'inserts text + paragraph', () => {
  409. setData( doc, '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  410. insertHelper( 'yyy<paragraph>xxx</paragraph>' );
  411. expect( getData( doc ) )
  412. .to.equal( '<paragraph>foo</paragraph><paragraph>yyy</paragraph><paragraph>xxx[]</paragraph><paragraph>bar</paragraph>' );
  413. } );
  414. it( 'inserts two blocks', () => {
  415. setData( doc, '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  416. insertHelper( '<heading1>xxx</heading1><paragraph>yyy</paragraph>' );
  417. expect( getData( doc ) )
  418. .to.equal( '<paragraph>foo</paragraph><heading1>xxx</heading1><paragraph>yyy[]</paragraph><paragraph>bar</paragraph>' );
  419. } );
  420. it( 'inserts block object', () => {
  421. setData( doc, '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  422. insertHelper( '<blockWidget></blockWidget>' );
  423. // It's enough, don't worry.
  424. expect( getData( doc ) ).to.equal( '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  425. } );
  426. it( 'inserts inline object', () => {
  427. setData( doc, '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  428. insertHelper( '<inlineWidget></inlineWidget>' );
  429. expect( getData( doc ) )
  430. .to.equal( '<paragraph>foo</paragraph><paragraph><inlineWidget></inlineWidget>[]</paragraph><paragraph>bar</paragraph>' );
  431. } );
  432. } );
  433. describe( 'content over an inline object', () => {
  434. it( 'inserts text', () => {
  435. setData( doc, '<paragraph>foo[<inlineWidget></inlineWidget>]bar</paragraph>' );
  436. insertHelper( 'xxx' );
  437. expect( getData( doc ) ).to.equal( '<paragraph>fooxxx[]bar</paragraph>' );
  438. } );
  439. it( 'inserts paragraph', () => {
  440. setData( doc, '<paragraph>foo[<inlineWidget></inlineWidget>]bar</paragraph>' );
  441. insertHelper( '<paragraph>xxx</paragraph>' );
  442. expect( getData( doc ) ).to.equal( '<paragraph>fooxxx[]bar</paragraph>' );
  443. } );
  444. it( 'inserts text + paragraph', () => {
  445. setData( doc, '<paragraph>foo[<inlineWidget></inlineWidget>]bar</paragraph>' );
  446. insertHelper( 'yyy<paragraph>xxx</paragraph>' );
  447. expect( getData( doc ) ).to.equal( '<paragraph>fooyyy</paragraph><paragraph>xxx[]bar</paragraph>' );
  448. } );
  449. it( 'inserts two blocks', () => {
  450. setData( doc, '<paragraph>foo[<inlineWidget></inlineWidget>]bar</paragraph>' );
  451. insertHelper( '<heading1>xxx</heading1><paragraph>yyy</paragraph>' );
  452. expect( getData( doc ) ).to.equal( '<paragraph>fooxxx</paragraph><paragraph>yyy[]bar</paragraph>' );
  453. } );
  454. it( 'inserts inline object', () => {
  455. setData( doc, '<paragraph>foo[<inlineWidget></inlineWidget>]bar</paragraph>' );
  456. insertHelper( '<inlineWidget></inlineWidget>' );
  457. expect( getData( doc ) ).to.equal( '<paragraph>foo<inlineWidget></inlineWidget>[]bar</paragraph>' );
  458. } );
  459. it( 'inserts block object', () => {
  460. setData( doc, '<paragraph>foo[<inlineWidget></inlineWidget>]bar</paragraph>' );
  461. insertHelper( '<blockWidget></blockWidget>' );
  462. expect( getData( doc ) ).to.equal( '<paragraph>foo</paragraph>[<blockWidget></blockWidget>]<paragraph>bar</paragraph>' );
  463. } );
  464. } );
  465. } );
  466. describe( 'filtering out', () => {
  467. beforeEach( () => {
  468. doc = new Document();
  469. doc.createRoot();
  470. dataController = new DataController( doc );
  471. const schema = doc.schema;
  472. schema.registerItem( 'paragraph', '$block' );
  473. // Let's use table as an example of content which needs to be filtered out.
  474. schema.registerItem( 'table' );
  475. schema.registerItem( 'td' );
  476. schema.registerItem( 'disallowedWidget' );
  477. schema.allow( { name: 'table', inside: '$clipboardHolder' } );
  478. schema.allow( { name: 'td', inside: '$clipboardHolder' } );
  479. schema.allow( { name: 'td', inside: 'table' } );
  480. schema.allow( { name: '$block', inside: 'td' } );
  481. schema.allow( { name: '$text', inside: 'td' } );
  482. schema.allow( { name: 'disallowedWidget', inside: '$clipboardHolder' } );
  483. schema.allow( { name: '$text', inside: 'disallowedWidget' } );
  484. schema.objects.add( 'disallowedWidget' );
  485. } );
  486. it( 'filters out disallowed elements and leaves out the text', () => {
  487. setData( doc, '<paragraph>f[]oo</paragraph>' );
  488. insertHelper( '<table><td>xxx</td><td>yyy</td></table>' );
  489. expect( getData( doc ) ).to.equal( '<paragraph>fxxxyyy[]oo</paragraph>' );
  490. } );
  491. it( 'filters out disallowed elements and leaves out the paragraphs', () => {
  492. setData( doc, '<paragraph>f[]oo</paragraph>' );
  493. insertHelper( '<table><td><paragraph>xxx</paragraph><paragraph>yyy</paragraph><paragraph>zzz</paragraph></td></table>' );
  494. expect( getData( doc ) ).to.equal( '<paragraph>fxxx</paragraph><paragraph>yyy</paragraph><paragraph>zzz[]oo</paragraph>' );
  495. } );
  496. it( 'filters out disallowed objects', () => {
  497. setData( doc, '<paragraph>f[]oo</paragraph>' );
  498. insertHelper( '<disallowedWidget>xxx</disallowedWidget>' );
  499. expect( getData( doc ) ).to.equal( '<paragraph>f[]oo</paragraph>' );
  500. } );
  501. } );
  502. } );
  503. describe( 'integration with limit elements', () => {
  504. beforeEach( () => {
  505. doc = new Document();
  506. doc.createRoot();
  507. dataController = new DataController( doc );
  508. const schema = doc.schema;
  509. schema.registerItem( 'limit' );
  510. schema.allow( { name: 'limit', inside: '$root' } );
  511. schema.allow( { name: '$text', inside: 'limit' } );
  512. schema.limits.add( 'limit' );
  513. schema.registerItem( 'disallowedElement' );
  514. schema.allow( { name: 'disallowedElement', inside: '$clipboardHolder' } );
  515. schema.registerItem( 'paragraph', '$block' );
  516. } );
  517. it( 'should insert limit element', () => {
  518. insertHelper( '<limit></limit>' );
  519. expect( getData( doc ) ).to.equal( '<limit>[]</limit>' );
  520. } );
  521. it( 'should insert text into limit element', () => {
  522. setData( doc, '<limit>[]</limit>' );
  523. insertHelper( 'foo bar' );
  524. expect( getData( doc ) ).to.equal( '<limit>foo bar[]</limit>' );
  525. } );
  526. it( 'should insert text into limit element', () => {
  527. setData( doc, '<limit>foo[</limit><limit>]bar</limit>' );
  528. insertHelper( 'baz' );
  529. expect( getData( doc ) ).to.equal( '<limit>foobaz[]</limit><limit>bar</limit>' );
  530. } );
  531. it( 'should not insert disallowed elements inside limit elements', () => {
  532. setData( doc, '<limit>[]</limit>' );
  533. insertHelper( '<disallowedElement></disallowedElement>' );
  534. expect( getData( doc ) ).to.equal( '<limit>[]</limit>' );
  535. } );
  536. it( 'should not leave the limit element when inserting at the end', () => {
  537. setData( doc, '<limit>foo[]</limit>' );
  538. insertHelper( '<paragraph>a</paragraph><paragraph>b</paragraph>' );
  539. expect( getData( doc ) ).to.equal( '<limit>fooab[]</limit>' );
  540. } );
  541. it( 'should not leave the limit element when inserting at the beginning', () => {
  542. setData( doc, '<limit>[]foo</limit>' );
  543. insertHelper( '<paragraph>a</paragraph><paragraph>b</paragraph>' );
  544. expect( getData( doc ) ).to.equal( '<limit>ab[]foo</limit>' );
  545. } );
  546. } );
  547. // Helper function that parses given content and inserts it at the cursor position.
  548. //
  549. // @param {module:engine/model/item~Item|String} content
  550. function insertHelper( content ) {
  551. if ( typeof content == 'string' ) {
  552. content = parse( content, doc.schema, {
  553. context: [ '$clipboardHolder' ]
  554. } );
  555. }
  556. insertContent( dataController, content, doc.selection );
  557. return content;
  558. }
  559. } );