8
0

clear.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import Writer from '../../../src/view/writer';
  6. import Range from '../../../src/view/range';
  7. import { stringify, parse } from '../../../src/dev-utils/view';
  8. import ContainerElement from '../../../src/view/containerelement';
  9. import AttributeElement from '../../../src/view/attributeelement';
  10. import EmptyElement from '../../../src/view/emptyelement';
  11. import UIElement from '../../../src/view/uielement';
  12. import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
  13. describe( 'Writer', () => {
  14. describe( 'clear()', () => {
  15. let writer;
  16. // Executes test using `parse` and `stringify` utils functions. Uses range delimiters `[]{}` to create ranges.
  17. //
  18. // @param {Object} elementToRemove
  19. // @param {String} input
  20. // @param {String} expectedResult
  21. function test( elementToRemove, input, expectedResult ) {
  22. const { view, selection } = parse( input );
  23. writer.clear( selection.getFirstRange(), elementToRemove );
  24. expect( stringify( view, null, { showType: true } ) ).to.equal( expectedResult );
  25. }
  26. before( () => {
  27. writer = new Writer();
  28. } );
  29. it( 'should throw when range placed in two containers', () => {
  30. const p1 = new ContainerElement( 'p' );
  31. const p2 = new ContainerElement( 'p' );
  32. expect( () => {
  33. writer.clear( Range.createFromParentsAndOffsets( p1, 0, p2, 0 ) );
  34. } ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
  35. } );
  36. it( 'should throw when range has no parent container', () => {
  37. const el = new AttributeElement( 'b' );
  38. expect( () => {
  39. writer.clear( Range.createFromParentsAndOffsets( el, 0, el, 0 ) );
  40. } ).to.throw( CKEditorError, 'view-writer-invalid-range-container' );
  41. } );
  42. it( 'should remove matched element from range', () => {
  43. const elementToRemove = new AttributeElement( 'b' );
  44. test(
  45. elementToRemove,
  46. '<container:p>[b<attribute:b>a</attribute:b>r]</container:p>',
  47. '<container:p>br</container:p>'
  48. );
  49. } );
  50. it( 'should remove matched element from range when range is inside text node', () => {
  51. const elementToRemove = new AttributeElement( 'b' );
  52. test(
  53. elementToRemove,
  54. '<container:p>F{o<attribute:b>o</attribute:b> ba}r</container:p>',
  55. '<container:p>Fo bar</container:p>'
  56. );
  57. } );
  58. it( 'should remove multiple matched elements from range', () => {
  59. const elementToRemove = new AttributeElement( 'b' );
  60. test(
  61. elementToRemove,
  62. '<container:p>[Fo<attribute:b>o</attribute:b> b<attribute:b>a</attribute:b>r]</container:p>',
  63. '<container:p>Fo br</container:p>'
  64. );
  65. } );
  66. it( 'should remove multiple matched elements from range when range is inside text node', () => {
  67. const elementToRemove = new AttributeElement( 'b' );
  68. test(
  69. elementToRemove,
  70. '<container:p>F{o<attribute:b>o</attribute:b> <attribute:b>b</attribute:b>a}r</container:p>',
  71. '<container:p>Fo ar</container:p>'
  72. );
  73. } );
  74. it( 'should remove only matched element', () => {
  75. const elementToRemove = new AttributeElement( 'b' );
  76. test(
  77. elementToRemove,
  78. '<container:p>F{o<attribute:i>o</attribute:i> <attribute:b>b</attribute:b>a}r</container:p>',
  79. '<container:p>Fo<attribute:i>o</attribute:i> ar</container:p>'
  80. );
  81. } );
  82. it( 'should remove part of node when range ends inside this node', () => {
  83. const elementToRemove = new AttributeElement( 'b' );
  84. test(
  85. elementToRemove,
  86. '<container:p>f{oo<attribute:b>ba}r</attribute:b></container:p>',
  87. '<container:p>foo<attribute:b>r</attribute:b></container:p>'
  88. );
  89. } );
  90. it( 'should remove part of node when range starts inside this node', () => {
  91. const elementToRemove = new AttributeElement( 'b' );
  92. test(
  93. elementToRemove,
  94. '<container:p>foo<attribute:b>b{ar</attribute:b>bi}z</container:p>',
  95. '<container:p>foo<attribute:b>b</attribute:b>biz</container:p>'
  96. );
  97. } );
  98. it( 'should remove part of node when range starts and ends inside this node', () => {
  99. const elementToRemove = new AttributeElement( 'b' );
  100. test(
  101. elementToRemove,
  102. '<container:p>foo<attribute:b>b{a}r</attribute:b>biz</container:p>',
  103. '<container:p>foo<attribute:b>br</attribute:b>biz</container:p>'
  104. );
  105. } );
  106. it( 'should merge after removing', () => {
  107. const elementToRemove = new AttributeElement( 'b' );
  108. test(
  109. elementToRemove,
  110. '<container:p>' +
  111. '<attribute:a>fo{o</attribute:a><attribute:b>a</attribute:b><attribute:a>b}iz</attribute:a>' +
  112. '</container:p>',
  113. '<container:p><attribute:a>foobiz</attribute:a></container:p>'
  114. );
  115. } );
  116. it( 'should remove EmptyElement', () => {
  117. const elementToRemove = new EmptyElement( 'img' );
  118. test(
  119. elementToRemove,
  120. '<container:p>f{oo<empty:img></empty:img>ba}r</container:p>',
  121. '<container:p>foobar</container:p>'
  122. );
  123. } );
  124. it( 'should remove UIElement', () => {
  125. const elementToRemove = new UIElement( 'span' );
  126. test(
  127. elementToRemove,
  128. '<container:p>f{oo<ui:span></ui:span>ba}r</container:p>',
  129. '<container:p>foobar</container:p>'
  130. );
  131. } );
  132. it( 'should remove ContainerElement', () => {
  133. const elementToRemove = new ContainerElement( 'p' );
  134. test(
  135. elementToRemove,
  136. '[<container:div>foo</container:div><container:p>bar</container:p><container:div>biz</container:div>]',
  137. '<container:div>foo</container:div><container:div>biz</container:div>'
  138. );
  139. } );
  140. } );
  141. } );