spellchecking.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* globals document */
  6. import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
  7. import Enter from '@ckeditor/ckeditor5-enter/src/enter';
  8. import Typing from '../src/typing';
  9. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  10. import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
  11. import Undo from '@ckeditor/ckeditor5-undo/src/undo';
  12. import ViewRange from '@ckeditor/ckeditor5-engine/src/view/range';
  13. import ViewSelection from '@ckeditor/ckeditor5-engine/src/view/selection';
  14. import { getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  15. import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
  16. describe( 'Typing – spellchecking integration', () => {
  17. let editor, container;
  18. beforeEach( () => {
  19. container = document.createElement( 'div' );
  20. document.body.appendChild( container );
  21. return ClassicEditor
  22. .create( container, {
  23. plugins: [ Enter, Typing, Paragraph, Bold, Undo ]
  24. } )
  25. .then( newEditor => {
  26. editor = newEditor;
  27. editor.setData(
  28. '<p>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</p>' +
  29. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  30. } );
  31. } );
  32. afterEach( () => {
  33. container.remove();
  34. return editor.destroy();
  35. } );
  36. describe( 'Plain text spellchecking (mutations)', () => {
  37. // This tests emulates spellchecker correction on non-styled text by firing proper mutations.
  38. it( 'should replace with longer word (collapsed)', () => {
  39. emulateSpellcheckerMutation( editor, 0, 13, 13,
  40. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  41. 'The Foo house a is a Foo hous e. A Foo athat and Foo xhat. This is an istane' );
  42. expectContent( editor,
  43. '<paragraph>The Foo house[] a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</paragraph>' +
  44. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  45. '<p>The Foo house{} a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</p>' +
  46. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  47. } );
  48. it( 'should replace with longer word (non-collapsed)', () => {
  49. emulateSpellcheckerMutation( editor, 0, 8, 13,
  50. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  51. 'The Foo house a is a Foo hous e. A Foo athat and Foo xhat. This is an istane' );
  52. expectContent( editor,
  53. '<paragraph>The Foo [house] a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</paragraph>' +
  54. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  55. '<p>The Foo {house} a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</p>' +
  56. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  57. } );
  58. it( 'should replace with shorter word (merging letter after - collapsed)', () => {
  59. emulateSpellcheckerMutation( editor, 0, 29, 29,
  60. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  61. 'The Foo hous a is a Foo house. A Foo athat and Foo xhat. This is an istane' );
  62. expectContent( editor,
  63. '<paragraph>The Foo hous a is a Foo house[]. A Foo athat and Foo xhat. This is an istane</paragraph>' +
  64. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  65. '<p>The Foo hous a is a Foo house{}. A Foo athat and Foo xhat. This is an istane</p>' +
  66. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  67. } );
  68. it( 'should replace with shorter word (merging letter after - non-collapsed)', () => {
  69. emulateSpellcheckerMutation( editor, 0, 24, 29,
  70. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  71. 'The Foo hous a is a Foo house. A Foo athat and Foo xhat. This is an istane' );
  72. expectContent( editor,
  73. '<paragraph>The Foo hous a is a Foo [house]. A Foo athat and Foo xhat. This is an istane</paragraph>' +
  74. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  75. '<p>The Foo hous a is a Foo {house}. A Foo athat and Foo xhat. This is an istane</p>' +
  76. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  77. } );
  78. it( 'should replace with same length text (collapsed)', () => {
  79. emulateSpellcheckerMutation( editor, 0, 43, 43,
  80. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  81. 'The Foo hous a is a Foo hous e. A Food that and Foo xhat. This is an istane' );
  82. expectContent( editor,
  83. '<paragraph>The Foo hous a is a Foo hous e. A Food that[] and Foo xhat. This is an istane</paragraph>' +
  84. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  85. '<p>The Foo hous a is a Foo hous e. A Food that{} and Foo xhat. This is an istane</p>' +
  86. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  87. } );
  88. it( 'should replace with same length text (non-collapsed)', () => {
  89. emulateSpellcheckerMutation( editor, 0, 37, 43,
  90. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  91. 'The Foo hous a is a Foo hous e. A Food that and Foo xhat. This is an istane' );
  92. expectContent( editor,
  93. '<paragraph>The Foo hous a is a Foo hous e. A Foo[d that] and Foo xhat. This is an istane</paragraph>' +
  94. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  95. '<p>The Foo hous a is a Foo hous e. A Foo{d that} and Foo xhat. This is an istane</p>' +
  96. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  97. } );
  98. it( 'should replace with longer word on the paragraph end (non-collapsed)', () => {
  99. emulateSpellcheckerMutation( editor, 0, 77, 77,
  100. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  101. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an instance' );
  102. expectContent( editor,
  103. '<paragraph>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an instance[]</paragraph>' +
  104. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  105. '<p>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an instance{}</p>' +
  106. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  107. } );
  108. it( 'should replace with longer word on the paragraph end (collapsed)', () => {
  109. emulateSpellcheckerMutation( editor, 0, 69, 77,
  110. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane',
  111. 'The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an instance' );
  112. expectContent( editor,
  113. '<paragraph>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an [instance]</paragraph>' +
  114. '<paragraph>Banana, orenge, appfle and the new comppputer</paragraph>',
  115. '<p>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an {instance}</p>' +
  116. '<p>Banana, orenge, appfle and the new comppputer</p>' );
  117. } );
  118. it( 'should replace with shorter word on the paragraph end (non-collapsed)', () => {
  119. emulateSpellcheckerMutation( editor, 1, 43, 43,
  120. 'Banana, orenge, appfle and the new comppputer',
  121. 'Banana, orenge, appfle and the new computer' );
  122. expectContent( editor,
  123. '<paragraph>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</paragraph>' +
  124. '<paragraph>Banana, orenge, appfle and the new computer[]</paragraph>',
  125. '<p>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</p>' +
  126. '<p>Banana, orenge, appfle and the new computer{}</p>' );
  127. } );
  128. it( 'should replace with shorter word on the paragraph end (collapsed)', () => {
  129. emulateSpellcheckerMutation( editor, 1, 35, 43,
  130. 'Banana, orenge, appfle and the new comppputer',
  131. 'Banana, orenge, appfle and the new computer' );
  132. expectContent( editor,
  133. '<paragraph>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</paragraph>' +
  134. '<paragraph>Banana, orenge, appfle and the new [computer]</paragraph>',
  135. '<p>The Foo hous a is a Foo hous e. A Foo athat and Foo xhat. This is an istane</p>' +
  136. '<p>Banana, orenge, appfle and the new {computer}</p>' );
  137. } );
  138. } );
  139. } );
  140. function emulateSpellcheckerMutation( editor, nodeIndex, rangeStart, rangeEnd, oldText, newText ) {
  141. const view = editor.editing.view;
  142. const viewRoot = view.document.getRoot();
  143. const viewSelection = new ViewSelection();
  144. const node = viewRoot.getChild( nodeIndex ).getChild( 0 );
  145. viewSelection.setTo( ViewRange.createFromParentsAndOffsets( node, rangeStart, node, rangeEnd ) );
  146. view.document.fire( 'mutations',
  147. [
  148. {
  149. type: 'text',
  150. oldText,
  151. newText,
  152. node
  153. }
  154. ],
  155. viewSelection
  156. );
  157. }
  158. function expectContent( editor, expectedModel, expectedView ) {
  159. expect( getModelData( editor.model ) ).to.equal( expectedModel );
  160. expect( getViewData( editor.editing.view ) ).to.equal( expectedView );
  161. }