modifyselection.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* bender-tags: model, composer */
  6. import Document from '/ckeditor5/engine/model/document.js';
  7. import Selection from '/ckeditor5/engine/model/selection.js';
  8. import modifySelection from '/ckeditor5/engine/model/composer/modifyselection.js';
  9. import { setData, stringify } from '/tests/engine/_utils/model.js';
  10. describe( 'Delete utils', () => {
  11. let document;
  12. beforeEach( () => {
  13. document = new Document();
  14. document.schema.registerItem( 'p', '$block' );
  15. document.schema.registerItem( 'x', '$block' );
  16. document.schema.registerItem( 'img', '$inline' );
  17. document.schema.allow( { name: '$text', inside: '$root' } );
  18. document.createRoot();
  19. } );
  20. describe( 'modifySelection', () => {
  21. describe( 'unit=character', () => {
  22. describe( 'within element', () => {
  23. test(
  24. 'does nothing on empty content',
  25. '[]',
  26. '[]'
  27. );
  28. test(
  29. 'does nothing on empty content (with empty element)',
  30. '<p>[]</p>',
  31. '<p>[]</p>'
  32. );
  33. test(
  34. 'does nothing on empty content (backward)',
  35. '[]',
  36. '[]',
  37. { direction: 'backward' }
  38. );
  39. test(
  40. 'does nothing on root boundary',
  41. '<p>foo[]</p>',
  42. '<p>foo[]</p>'
  43. );
  44. test(
  45. 'does nothing on root boundary (backward)',
  46. '<p>[]foo</p>',
  47. '<p>[]foo</p>',
  48. { direction: 'backward' }
  49. );
  50. test(
  51. 'extends one character forward',
  52. '<p>f[]oo</p>',
  53. '<p>f[o]o</p>'
  54. );
  55. test(
  56. 'extends one character backward',
  57. '<p>fo[]o</p>',
  58. '<p>f<selection backward>o]o</p>',
  59. { direction: 'backward' }
  60. );
  61. test(
  62. 'extends one character forward (non-collapsed)',
  63. '<p>f[o]obar</p>',
  64. '<p>f[oo]bar</p>'
  65. );
  66. test(
  67. 'extends one character backward (non-collapsed)',
  68. '<p>foob<selection backward>a]r</p>',
  69. '<p>foo<selection backward>ba]r</p>',
  70. { direction: 'backward' }
  71. );
  72. test(
  73. 'extends to element boundary',
  74. '<p>fo[]o</p>',
  75. '<p>fo[o]</p>'
  76. );
  77. test(
  78. 'extends to element boundary (backward)',
  79. '<p>f[]oo</p>',
  80. '<p><selection backward>f]oo</p>',
  81. { direction: 'backward' }
  82. );
  83. test(
  84. 'shrinks forward selection (to collapsed)',
  85. '<p>foo[b]ar</p>',
  86. '<p>foo[]bar</p>',
  87. { direction: 'backward' }
  88. );
  89. test(
  90. 'shrinks backward selection (to collapsed)',
  91. '<p>foo<selection backward>b]ar</p>',
  92. '<p>foob[]ar</p>'
  93. );
  94. test(
  95. 'extends one element forward',
  96. '<p>f[]<img></img>oo</p>',
  97. '<p>f[<img></img>]oo</p>'
  98. );
  99. test(
  100. 'extends one non-empty element forward',
  101. '<p>f[]<img>x</img>oo</p>',
  102. '<p>f[<img>x</img>]oo</p>'
  103. );
  104. test(
  105. 'extends one element backward',
  106. '<p>fo<img></img>[]o</p>',
  107. '<p>fo<selection backward><img></img>]o</p>',
  108. { direction: 'backward' }
  109. );
  110. test(
  111. 'unicode support - combining mark forward',
  112. '<p>foo[]b̂ar</p>',
  113. '<p>foo[b̂]ar</p>'
  114. );
  115. test(
  116. 'unicode support - combining mark backward',
  117. '<p>foob̂[]ar</p>',
  118. '<p>foo<selection backward>b̂]ar</p>',
  119. { direction: 'backward' }
  120. );
  121. test(
  122. 'unicode support - combining mark multiple',
  123. '<p>fo[]o̻̐ͩbar</p>',
  124. '<p>fo[o̻̐ͩ]bar</p>'
  125. );
  126. test(
  127. 'unicode support - combining mark multiple backward',
  128. '<p>foo̻̐ͩ[]bar</p>',
  129. '<p>fo<selection backward>o̻̐ͩ]bar</p>',
  130. { direction: 'backward' }
  131. );
  132. test(
  133. 'unicode support - combining mark to the end',
  134. '<p>fo[]o̻̐ͩ</p>',
  135. '<p>fo[o̻̐ͩ]</p>'
  136. );
  137. test(
  138. 'unicode support - surrogate pairs forward',
  139. '<p>[]\uD83D\uDCA9</p>',
  140. '<p>[\uD83D\uDCA9]</p>'
  141. );
  142. test(
  143. 'unicode support - surrogate pairs backward',
  144. '<p>\uD83D\uDCA9[]</p>',
  145. '<p><selection backward>\uD83D\uDCA9]</p>',
  146. { direction: 'backward' }
  147. );
  148. } );
  149. describe( 'beyond element', () => {
  150. test(
  151. 'extends over boundary of empty elements',
  152. '<p>[]</p><p></p><p></p>',
  153. '<p>[</p><p>]</p><p></p>'
  154. );
  155. test(
  156. 'extends over boundary of empty elements (backward)',
  157. '<p></p><p></p><p>[]</p>',
  158. '<p></p><p><selection backward></p><p>]</p>',
  159. { direction: 'backward' }
  160. );
  161. test(
  162. 'extends over boundary of non-empty elements',
  163. '<p>a[]</p><p>bcd</p>',
  164. '<p>a[</p><p>]bcd</p>'
  165. );
  166. test(
  167. 'extends over boundary of non-empty elements (backward)',
  168. '<p>a</p><p>[]bcd</p>',
  169. '<p>a<selection backward></p><p>]bcd</p>',
  170. { direction: 'backward' }
  171. );
  172. test(
  173. 'extends over character after boundary',
  174. '<p>a[</p><p>]bcd</p>',
  175. '<p>a[</p><p>b]cd</p>'
  176. );
  177. test(
  178. 'extends over character after boundary (backward)',
  179. '<p>abc<selection backward></p><p>]d</p>',
  180. '<p>ab<selection backward>c</p><p>]d</p>',
  181. { direction: 'backward' }
  182. );
  183. test(
  184. 'extends over boundary when next element has nested elements',
  185. '<p>a[]</p><p><x>bcd</x></p>',
  186. '<p>a[</p><p>]<x>bcd</x></p>'
  187. );
  188. test(
  189. 'extends over element when next element has nested elements',
  190. '<p>a[</p><p>]<x>bcd</x>ef</p>',
  191. '<p>a[</p><p><x>bcd</x>]ef</p>'
  192. );
  193. test(
  194. 'extends over element when next node is a text',
  195. '<p>a[]</p>bc',
  196. '<p>a[</p>]bc'
  197. );
  198. test(
  199. 'extends over element when next node is a text (backward)',
  200. 'ab<p>[]c</p>',
  201. 'ab<selection backward><p>]c</p>',
  202. { direction: 'backward' }
  203. );
  204. test(
  205. 'shrinks over boundary of empty elements',
  206. '<p><selection backward></p><p>]</p>',
  207. '<p></p><p>[]</p>'
  208. );
  209. test(
  210. 'shrinks over boundary of empty elements (backward)',
  211. '<p>[</p><p>]</p>',
  212. '<p>[]</p><p></p>',
  213. { direction: 'backward' }
  214. );
  215. test(
  216. 'shrinks over boundary of non-empty elements',
  217. '<p>a<selection backward></p><p>]b</p>',
  218. '<p>a</p><p>[]b</p>'
  219. );
  220. test(
  221. 'shrinks over boundary of non-empty elements (backward)',
  222. '<p>a[</p><p>]b</p>',
  223. '<p>a[]</p><p>b</p>',
  224. { direction: 'backward' }
  225. );
  226. test(
  227. 'updates selection attributes',
  228. '<p><$text bold="true">foo</$text>[b]</p>',
  229. '<p><$text bold="true>"foo</$text><selection bold=true />b</p>',
  230. { direction: 'backward' }
  231. );
  232. } );
  233. } );
  234. describe( 'unit=codePoint', () => {
  235. test(
  236. 'does nothing on empty content',
  237. '[]',
  238. '[]',
  239. { unit: 'codePoint' }
  240. );
  241. test(
  242. 'does nothing on empty content (with empty element)',
  243. '<p>[]</p>',
  244. '<p>[]</p>',
  245. { unit: 'codePoint' }
  246. );
  247. test(
  248. 'extends one user-perceived character forward - latin letters',
  249. '<p>f[]oo</p>',
  250. '<p>f[o]o</p>',
  251. { unit: 'codePoint' }
  252. );
  253. test(
  254. 'extends one user-perceived character backward - latin letters',
  255. '<p>fo[]o</p>',
  256. '<p>f<selection backward>o]o</p>',
  257. { unit: 'codePoint', direction: 'backward' }
  258. );
  259. test(
  260. 'unicode support - combining mark forward',
  261. '<p>foo[]b̂ar</p>',
  262. '<p>foo[b]̂ar</p>',
  263. { unit: 'codePoint' }
  264. );
  265. test(
  266. 'unicode support - combining mark backward',
  267. '<p>foob̂[]ar</p>',
  268. '<p>foob<selection backward>̂]ar</p>',
  269. { unit: 'codePoint', direction: 'backward' }
  270. );
  271. test(
  272. 'unicode support - combining mark multiple',
  273. '<p>fo[]o̻̐ͩbar</p>',
  274. '<p>fo[o]̻̐ͩbar</p>',
  275. { unit: 'codePoint' }
  276. );
  277. test(
  278. 'unicode support - surrogate pairs forward',
  279. '<p>[]\uD83D\uDCA9</p>',
  280. '<p>[\uD83D\uDCA9]</p>',
  281. { unit: 'codePoint' }
  282. );
  283. test(
  284. 'unicode support surrogate pairs backward',
  285. '<p>\uD83D\uDCA9[]</p>',
  286. '<p><selection backward>\uD83D\uDCA9]</p>',
  287. { unit: 'codePoint', direction: 'backward' }
  288. );
  289. } );
  290. } );
  291. function test( title, input, output, options, isBackward ) {
  292. it( title, () => {
  293. input = input.normalize();
  294. output = output.normalize();
  295. setData( document, input );
  296. // Creating new instance of selection instead of operation on engine.model.Document#selection.
  297. // Document's selection will throw errors in some test cases (which are correct cases, but only for
  298. // non-document selections).
  299. const testSelection = Selection.createFromSelection( document.selection );
  300. modifySelection( testSelection, options );
  301. expect( stringify( document.getRoot(), testSelection ) ).to.equal( output );
  302. expect( document.selection.isBackward ).to.equal( !!isBackward );
  303. } );
  304. }
  305. } );