8
0

remove.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* bender-tags: treeview */
  6. 'use strict';
  7. import Writer from '/ckeditor5/engine/treeview/writer.js';
  8. import Element from '/ckeditor5/engine/treeview/element.js';
  9. import Range from '/ckeditor5/engine/treeview/range.js';
  10. import Text from '/ckeditor5/engine/treeview/text.js';
  11. import DocumentFragment from '/ckeditor5/engine/treeview/documentfragment.js';
  12. import utils from '/tests/engine/treeview/writer/_utils/utils.js';
  13. describe( 'Writer', () => {
  14. const create = utils.create;
  15. const test = utils.test;
  16. let writer;
  17. beforeEach( () => {
  18. writer = new Writer();
  19. } );
  20. describe( 'remove', () => {
  21. it( 'should throw when range placed in two containers', () => {
  22. const p1 = new Element( 'p' );
  23. const p2 = new Element( 'p' );
  24. expect( () => {
  25. writer.remove( Range.createFromParentsAndOffsets( p1, 0, p2, 0 ) );
  26. } ).to.throw( 'treeview-writer-invalid-range-container' );
  27. } );
  28. it( 'should return empty DocumentFragment when range is collapsed', () => {
  29. const p = new Element( 'p' );
  30. const range = Range.createFromParentsAndOffsets( p, 0, p, 0 );
  31. const fragment = writer.remove( range );
  32. expect( fragment ).to.be.instanceof( DocumentFragment );
  33. expect( fragment.getChildCount() ).to.equal( 0 );
  34. expect( range.isCollapsed ).to.be.true;
  35. } );
  36. it( 'should remove single text node', () => {
  37. // <p>[{foobar}]</p> -> <p>|</p>
  38. const created = create( writer, {
  39. instanceOf: Element,
  40. name: 'p',
  41. rangeStart: 0,
  42. rangeEnd: 1,
  43. children: [
  44. { instanceOf: Text, data: 'foobar' }
  45. ]
  46. } );
  47. const removed = writer.remove( created.range );
  48. test( writer, created.range.start, created.node, {
  49. instanceOf: Element,
  50. name: 'p',
  51. position: 0,
  52. children: []
  53. } );
  54. // Test removed nodes.
  55. test( writer, null, Array.from( removed.getChildren() ), [
  56. { instanceOf: Text, data: 'foobar' }
  57. ] );
  58. } );
  59. it( 'should not leave empty text nodes', () => {
  60. // <p>{[foobar]}</p> -> <p>|</p>
  61. const created = create( writer, {
  62. instanceOf: Element,
  63. name: 'p',
  64. children: [
  65. { instanceOf: Text, data: 'foobar', rangeStart: 0, rangeEnd: 6 }
  66. ]
  67. } );
  68. const removed = writer.remove( created.range );
  69. test( writer, created.range.start, created.node, {
  70. instanceOf: Element,
  71. name: 'p',
  72. position: 0,
  73. children: []
  74. } );
  75. // Test removed nodes.
  76. test( writer, null, removed, [
  77. { instanceOf: Text, data: 'foobar' }
  78. ] );
  79. } );
  80. it( 'should remove part of the text node', () => {
  81. // <p>{f[oob]ar}</p> -> <p>{f|ar}</p>
  82. const created = create( writer, {
  83. instanceOf: Element,
  84. name: 'p',
  85. children: [
  86. { instanceOf: Text, data: 'foobar', rangeStart: 1, rangeEnd: 4 }
  87. ]
  88. } );
  89. const removed = writer.remove( created.range );
  90. test( writer, created.range.start, created.node, {
  91. instanceOf: Element,
  92. name: 'p',
  93. children: [
  94. { instanceOf: Text, data: 'far', position: 1 }
  95. ]
  96. } );
  97. // Test removed nodes.
  98. test( writer, null, removed, [
  99. { instanceOf: Text, data: 'oob' }
  100. ] );
  101. } );
  102. it( 'should remove parts of nodes', () => {
  103. // <p>{f[oo}<b>{ba]r}</b></p> -> <p>{f}|<b>r</b></p>
  104. const created = create( writer, {
  105. instanceOf: Element,
  106. name: 'p',
  107. children: [
  108. { instanceOf: Text, data: 'foo', rangeStart: 1 },
  109. {
  110. instanceOf: Element,
  111. name: 'b',
  112. priority: 1,
  113. children: [
  114. { instanceOf: Text, data: 'bar', rangeEnd: 2 }
  115. ]
  116. }
  117. ]
  118. } );
  119. const removed = writer.remove( created.range );
  120. test( writer, created.range.start, created.node, {
  121. instanceOf: Element,
  122. name: 'p',
  123. position: 1,
  124. children: [
  125. { instanceOf: Text, data: 'f' },
  126. {
  127. instanceOf: Element,
  128. name: 'b',
  129. priority: 1,
  130. children: [
  131. { instanceOf: Text, data: 'r' }
  132. ]
  133. }
  134. ]
  135. } );
  136. // Test removed nodes.
  137. test( writer, null, removed, [
  138. { instanceOf: Text, data: 'oo' },
  139. {
  140. instanceOf: Element,
  141. priority: 1,
  142. name: 'b',
  143. children: [
  144. { instanceOf: Text, data: 'ba' }
  145. ]
  146. }
  147. ] );
  148. } );
  149. it( 'should merge after removing #1', () => {
  150. // <p><b>foo</b>[{bar}]<b>bazqux</b></p> -> <p><b>foo|bazqux</b></p>
  151. const created = create( writer, {
  152. instanceOf: Element,
  153. name: 'p',
  154. rangeStart: 1,
  155. rangeEnd: 2,
  156. children: [
  157. {
  158. instanceOf: Element,
  159. name: 'b',
  160. priority: 1,
  161. children: [
  162. { instanceOf: Text, data: 'foo' }
  163. ]
  164. },
  165. { instanceOf: Text, data: 'bar' },
  166. {
  167. instanceOf: Element,
  168. name: 'b',
  169. priority: 1,
  170. children: [
  171. { instanceOf: Text, data: 'bazqux' }
  172. ]
  173. }
  174. ]
  175. } );
  176. const removed = writer.remove( created.range );
  177. test( writer, created.range.start, created.node, {
  178. instanceOf: Element,
  179. name: 'p',
  180. children: [
  181. {
  182. instanceOf: Element,
  183. name: 'b',
  184. priority: 1,
  185. children: [
  186. { instanceOf: Text, data: 'foobazqux', position: 3 }
  187. ]
  188. }
  189. ]
  190. } );
  191. // Test removed nodes.
  192. test( writer, null, removed, [
  193. { instanceOf: Text, data: 'bar' }
  194. ] );
  195. } );
  196. it( 'should merge after removing #2', () => {
  197. // <p><b>fo[o</b>{bar}<b>ba]zqux</b></p> -> <p><b>fo|zqux</b></p>
  198. const created = create( writer, {
  199. instanceOf: Element,
  200. name: 'p',
  201. children: [
  202. {
  203. instanceOf: Element,
  204. name: 'b',
  205. priority: 1,
  206. children: [
  207. { instanceOf: Text, data: 'foo', rangeStart: 2 }
  208. ]
  209. },
  210. { instanceOf: Text, data: 'bar' },
  211. {
  212. instanceOf: Element,
  213. name: 'b',
  214. priority: 1,
  215. children: [
  216. { instanceOf: Text, data: 'bazqux', rangeEnd: 2 }
  217. ]
  218. }
  219. ]
  220. } );
  221. const removed = writer.remove( created.range );
  222. test( writer, created.range.start, created.node, {
  223. instanceOf: Element,
  224. name: 'p',
  225. children: [
  226. {
  227. instanceOf: Element,
  228. name: 'b',
  229. priority: 1,
  230. children: [
  231. { instanceOf: Text, data: 'fozqux', position: 2 }
  232. ]
  233. }
  234. ]
  235. } );
  236. // Test removed nodes.
  237. test( writer, null, removed, [
  238. {
  239. instanceOf: Element,
  240. priority: 1,
  241. name: 'b',
  242. children: [
  243. { instanceOf: Text, data: 'o' }
  244. ]
  245. },
  246. { instanceOf: Text, data: 'bar' },
  247. {
  248. instanceOf: Element,
  249. priority: 1,
  250. name: 'b',
  251. children: [
  252. { instanceOf: Text, data: 'ba' }
  253. ]
  254. }
  255. ] );
  256. } );
  257. } );
  258. } );