tablekeyboard.js 116 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. import TableKeyboard from '../src/tablekeyboard';
  6. import Table from '../src/table';
  7. import TableEditing from '../src/tableediting';
  8. import TableSelection from '../src/tableselection';
  9. import { modelTable } from './_utils/utils';
  10. import { getTableCellsContainingSelection } from '../src/utils/selection';
  11. import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
  12. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  13. import ImageEditing from '@ckeditor/ckeditor5-image/src/image/imageediting';
  14. import MediaEmbedEditing from '@ckeditor/ckeditor5-media-embed/src/mediaembedediting';
  15. import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
  16. import Image from '@ckeditor/ckeditor5-image/src/image';
  17. import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
  18. import HorizontalLine from '@ckeditor/ckeditor5-horizontal-line/src/horizontalline';
  19. import MediaEmbed from '@ckeditor/ckeditor5-media-embed/src/mediaembed';
  20. import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
  21. import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  22. import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
  23. import global from '@ckeditor/ckeditor5-utils/src/dom/global';
  24. import env from '@ckeditor/ckeditor5-utils/src/env';
  25. describe( 'TableKeyboard', () => {
  26. let editor, model, modelRoot, tableSelection, tableKeyboard, selection, editorElement;
  27. const imageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAUCAQAAADRyVAeAAAAKklEQVR42u3PAQ0AAAwCI' +
  28. 'O0f+u/hoAHNZUJFRERERERERERERERERLYiD9N4FAFj2iK6AAAAAElFTkSuQmCC';
  29. beforeEach( async () => {
  30. editorElement = global.document.createElement( 'div' );
  31. global.document.body.appendChild( editorElement );
  32. editor = await ClassicTestEditor.create( editorElement, {
  33. plugins: [ Table, Paragraph, Image, ImageCaption, HorizontalLine, MediaEmbed ]
  34. } );
  35. model = editor.model;
  36. selection = model.document.selection;
  37. modelRoot = model.document.getRoot();
  38. tableSelection = editor.plugins.get( TableSelection );
  39. tableKeyboard = editor.plugins.get( TableKeyboard );
  40. } );
  41. afterEach( async () => {
  42. editorElement.remove();
  43. await editor.destroy();
  44. } );
  45. it( 'should have pluginName', () => {
  46. expect( TableKeyboard.pluginName ).to.equal( 'TableKeyboard' );
  47. } );
  48. describe( 'Tab key handling', () => {
  49. let domEvtDataStub;
  50. beforeEach( () => {
  51. domEvtDataStub = {
  52. keyCode: getCode( 'Tab' ),
  53. preventDefault: sinon.spy(),
  54. stopPropagation: sinon.spy()
  55. };
  56. } );
  57. it( 'should do nothing if pressed other key', () => {
  58. setModelData( model, modelTable( [
  59. [ '11', '12[]' ]
  60. ] ) );
  61. domEvtDataStub.keyCode = getCode( 'a' );
  62. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  63. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  64. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  65. assertEqualMarkup( getModelData( model ), modelTable( [
  66. [ '11', '12[]' ]
  67. ] ) );
  68. } );
  69. it( 'should do nothing if Ctrl+Tab is pressed', () => {
  70. setModelData( model, modelTable( [
  71. [ '11', '12[]' ]
  72. ] ) );
  73. domEvtDataStub.ctrlKey = true;
  74. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  75. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  76. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  77. assertEqualMarkup( getModelData( model ), modelTable( [
  78. [ '11', '12[]' ]
  79. ] ) );
  80. } );
  81. describe( 'on Tab key press', () => {
  82. it( 'should do nothing if the selection is not in a table', () => {
  83. setModelData( model, '<paragraph>[]</paragraph>' + modelTable( [ [ '11', '12' ] ] ) );
  84. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  85. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  86. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  87. assertEqualMarkup( getModelData( model ), '<paragraph>[]</paragraph>' + modelTable( [
  88. [ '11', '12' ]
  89. ] ) );
  90. } );
  91. it( 'should move to the next cell', () => {
  92. setModelData( model, modelTable( [
  93. [ '11[]', '12' ]
  94. ] ) );
  95. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  96. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  97. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  98. assertEqualMarkup( getModelData( model ), modelTable( [
  99. [ '11', '[12]' ]
  100. ] ) );
  101. } );
  102. it( 'should create another row and move to the first cell in a new row', () => {
  103. setModelData( model, modelTable( [
  104. [ '11', '[12]' ]
  105. ] ) );
  106. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  107. assertEqualMarkup( getModelData( model ), modelTable( [
  108. [ '11', '12' ],
  109. [ '[]', '' ]
  110. ] ) );
  111. } );
  112. it( 'should select the whole table if the "insertTableRowBelow" command is disabled', () => {
  113. setModelData( model, modelTable( [
  114. [ '11', '12[]' ]
  115. ] ) );
  116. const insertTableRowBelowCommand = editor.commands.get( 'insertTableRowBelow' );
  117. insertTableRowBelowCommand.forceDisabled( 'test' );
  118. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  119. assertEqualMarkup( getModelData( model ),
  120. '[' + modelTable( [ [ '11', '12' ] ] ) + ']'
  121. );
  122. } );
  123. it( 'should move to the first cell of the next row if at the end of a row', () => {
  124. setModelData( model, modelTable( [
  125. [ '11', '12[]' ],
  126. [ '21', '22' ]
  127. ] ) );
  128. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  129. assertEqualMarkup( getModelData( model ), modelTable( [
  130. [ '11', '12' ],
  131. [ '[21]', '22' ]
  132. ] ) );
  133. } );
  134. it( 'should move to the next table cell if the block content is partially selected', () => {
  135. setModelData( model, modelTable( [
  136. [ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ]
  137. ] ) );
  138. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  139. assertEqualMarkup( getModelData( model ), modelTable( [
  140. [
  141. '11',
  142. '<paragraph>12</paragraph><paragraph>foo</paragraph><paragraph>bar</paragraph>',
  143. '[13]'
  144. ]
  145. ] ) );
  146. } );
  147. it( 'should move to the next cell containing an image', () => {
  148. setModelData( model, modelTable( [
  149. [ '11[]', '<paragraph>foo</paragraph><image><caption></caption></image>' ]
  150. ] ) );
  151. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  152. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  153. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  154. assertEqualMarkup( getModelData( model ), modelTable( [
  155. [ '11', '<paragraph>[foo</paragraph><image><caption></caption></image>]' ]
  156. ] ) );
  157. } );
  158. it( 'should move to the next cell containing a block quote', () => {
  159. model.schema.register( 'blockQuote', {
  160. allowWhere: '$block',
  161. allowContentOf: '$root'
  162. } );
  163. editor.conversion.elementToElement( { model: 'blockQuote', view: 'blockquote' } );
  164. setModelData( model, modelTable( [
  165. [ '11[]', '<blockQuote><paragraph>foo</paragraph></blockQuote>' ]
  166. ] ) );
  167. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  168. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  169. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  170. assertEqualMarkup( getModelData( model ), modelTable( [
  171. [ '11', '<blockQuote><paragraph>[foo]</paragraph></blockQuote>' ]
  172. ] ) );
  173. } );
  174. it( 'should listen with the lower priority than its children', () => {
  175. // Cancel TAB event.
  176. editor.keystrokes.set( 'Tab', ( data, cancel ) => cancel() );
  177. setModelData( model, modelTable( [
  178. [ '11[]', '12' ]
  179. ] ) );
  180. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  181. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  182. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  183. assertEqualMarkup( getModelData( model ), modelTable( [
  184. [ '11[]', '12' ]
  185. ] ) );
  186. } );
  187. describe( 'on table widget selected', () => {
  188. beforeEach( () => {
  189. editor.model.schema.register( 'block', {
  190. allowWhere: '$block',
  191. allowContentOf: '$block',
  192. isObject: true
  193. } );
  194. editor.conversion.elementToElement( { model: 'block', view: 'block' } );
  195. } );
  196. it( 'should move caret to the first table cell on TAB', () => {
  197. const spy = sinon.spy();
  198. editor.keystrokes.set( 'Tab', spy, { priority: 'lowest' } );
  199. setModelData( model, '[' + modelTable( [
  200. [ '11', '12' ]
  201. ] ) + ']' );
  202. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  203. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  204. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  205. assertEqualMarkup( getModelData( model ), modelTable( [
  206. [ '[11]', '12' ]
  207. ] ) );
  208. // Should cancel event - so no other tab handler is called.
  209. sinon.assert.notCalled( spy );
  210. } );
  211. it( 'shouldn\'t do anything on other blocks', () => {
  212. const spy = sinon.spy();
  213. editor.editing.view.document.on( 'keydown', spy );
  214. setModelData( model, '[<block>foo</block>]' );
  215. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  216. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  217. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  218. assertEqualMarkup( getModelData( model ), '[<block>foo</block>]' );
  219. // Should not cancel event.
  220. sinon.assert.calledOnce( spy );
  221. } );
  222. } );
  223. } );
  224. describe( 'on Shift+Tab key press', () => {
  225. beforeEach( () => {
  226. domEvtDataStub.shiftKey = true;
  227. } );
  228. it( 'should do nothing if the selection is not in a table', () => {
  229. setModelData( model, '<paragraph>[]</paragraph>' + modelTable( [
  230. [ '11', '12' ]
  231. ] ) );
  232. domEvtDataStub.keyCode = getCode( 'Tab' );
  233. domEvtDataStub.shiftKey = true;
  234. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  235. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  236. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  237. assertEqualMarkup( getModelData( model ), '<paragraph>[]</paragraph>' + modelTable( [
  238. [ '11', '12' ]
  239. ] ) );
  240. } );
  241. it( 'should move to the previous cell', () => {
  242. setModelData( model, modelTable( [
  243. [ '11', '12[]' ]
  244. ] ) );
  245. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  246. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  247. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  248. assertEqualMarkup( getModelData( model ), modelTable( [
  249. [ '[11]', '12' ]
  250. ] ) );
  251. } );
  252. it( 'should select the whole table if the caret is in the first table cell', () => {
  253. setModelData( model, '<paragraph>foo</paragraph>' + modelTable( [
  254. [ '[]11', '12' ]
  255. ] ) );
  256. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  257. assertEqualMarkup( getModelData( model ),
  258. '<paragraph>foo</paragraph>[' + modelTable( [ [ '11', '12' ] ] ) + ']'
  259. );
  260. } );
  261. it( 'should move to the last cell of a previous row if at the beginning of a row', () => {
  262. setModelData( model, modelTable( [
  263. [ '11', '12' ],
  264. [ '[]21', '22' ]
  265. ] ) );
  266. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  267. assertEqualMarkup( getModelData( model ), modelTable( [
  268. [ '11', '[12]' ],
  269. [ '21', '22' ]
  270. ] ) );
  271. } );
  272. it( 'should move to the previous table cell if the block content is partially selected', () => {
  273. setModelData( model, modelTable( [
  274. [ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ]
  275. ] ) );
  276. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  277. assertEqualMarkup( getModelData( model ), modelTable( [
  278. [
  279. '[11]',
  280. '<paragraph>12</paragraph><paragraph>foo</paragraph><paragraph>bar</paragraph>',
  281. '13'
  282. ]
  283. ] ) );
  284. } );
  285. it( 'should move to the previous cell containing an image', () => {
  286. setModelData( model, modelTable( [
  287. [ '<paragraph>foo</paragraph><image><caption></caption></image>', 'bar[]' ]
  288. ] ) );
  289. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  290. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  291. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  292. assertEqualMarkup( getModelData( model ), modelTable( [
  293. [ '<paragraph>[foo</paragraph><image><caption></caption></image>]', 'bar' ]
  294. ] ) );
  295. } );
  296. } );
  297. } );
  298. describe( 'Arrow keys handling', () => {
  299. let leftArrowDomEvtDataStub, rightArrowDomEvtDataStub, upArrowDomEvtDataStub, downArrowDomEvtDataStub;
  300. beforeEach( () => {
  301. leftArrowDomEvtDataStub = {
  302. keyCode: getCode( 'ArrowLeft' ),
  303. preventDefault: sinon.spy(),
  304. stopPropagation: sinon.spy(),
  305. domTarget: global.document.body
  306. };
  307. rightArrowDomEvtDataStub = {
  308. keyCode: getCode( 'ArrowRight' ),
  309. preventDefault: sinon.spy(),
  310. stopPropagation: sinon.spy(),
  311. domTarget: global.document.body
  312. };
  313. upArrowDomEvtDataStub = {
  314. keyCode: getCode( 'ArrowUp' ),
  315. preventDefault: sinon.spy(),
  316. stopPropagation: sinon.spy(),
  317. domTarget: global.document.body
  318. };
  319. downArrowDomEvtDataStub = {
  320. keyCode: getCode( 'ArrowDown' ),
  321. preventDefault: sinon.spy(),
  322. stopPropagation: sinon.spy(),
  323. domTarget: global.document.body
  324. };
  325. } );
  326. it( 'should do nothing if pressed some non-arrow key', () => {
  327. setModelData( model, modelTable( [
  328. [ '00', '01[]' ]
  329. ] ) );
  330. leftArrowDomEvtDataStub.keyCode = getCode( 'a' );
  331. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  332. sinon.assert.notCalled( leftArrowDomEvtDataStub.preventDefault );
  333. sinon.assert.notCalled( leftArrowDomEvtDataStub.stopPropagation );
  334. assertEqualMarkup( getModelData( model ), modelTable( [
  335. [ '00', '01[]' ]
  336. ] ) );
  337. } );
  338. it( 'should do nothing if the selection is not in a table', () => {
  339. const modelData = '<paragraph>[]foobar</paragraph>' + modelTable( [ [ '00', '01' ] ] );
  340. setModelData( model, modelData );
  341. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  342. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  343. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  344. assertEqualMarkup( getModelData( model ), modelData );
  345. } );
  346. describe( '#_navigateFromCellInDirection (finding a proper cell to move the selection to)', () => {
  347. describe( 'with no col/row-spanned cells', () => {
  348. beforeEach( () => {
  349. setModelData( model, '<paragraph>foo</paragraph>' + modelTable( [
  350. [ '00', '01', '02' ],
  351. [ '10', '11', '12' ],
  352. [ '20', '21', '22' ]
  353. ] ) + '<paragraph>bar</paragraph>' );
  354. } );
  355. describe( 'from the first table cell', () => {
  356. let tableCell;
  357. beforeEach( () => {
  358. tableCell = modelRoot.getNodeByPath( [ 1, 0, 0 ] );
  359. } );
  360. it( 'should navigate to the start position of the cell on the right when the direction is "right"', () => {
  361. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  362. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  363. [ '00', '[]01', '02' ],
  364. [ '10', '11', '12' ],
  365. [ '20', '21', '22' ]
  366. ] ) + '<paragraph>bar</paragraph>' );
  367. } );
  368. it( 'should navigate to the start position of the cell below when the direction is "down"', () => {
  369. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  370. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  371. [ '00', '01', '02' ],
  372. [ '[]10', '11', '12' ],
  373. [ '20', '21', '22' ]
  374. ] ) + '<paragraph>bar</paragraph>' );
  375. } );
  376. it( 'should select a whole table when the direction is "up"', () => {
  377. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  378. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>[' + modelTable( [
  379. [ '00', '01', '02' ],
  380. [ '10', '11', '12' ],
  381. [ '20', '21', '22' ]
  382. ] ) + ']<paragraph>bar</paragraph>' );
  383. } );
  384. it( 'should select a whole table when the direction is "left"', () => {
  385. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  386. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>[' + modelTable( [
  387. [ '00', '01', '02' ],
  388. [ '10', '11', '12' ],
  389. [ '20', '21', '22' ]
  390. ] ) + ']<paragraph>bar</paragraph>' );
  391. } );
  392. } );
  393. describe( 'from the last table cell', () => {
  394. let tableCell;
  395. beforeEach( () => {
  396. tableCell = modelRoot.getNodeByPath( [ 1, 2, 2 ] );
  397. } );
  398. it( 'should navigate to the end position of the cell on the left when the direction is "left"', () => {
  399. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  400. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  401. [ '00', '01', '02' ],
  402. [ '10', '11', '12' ],
  403. [ '20', '21[]', '22' ]
  404. ] ) + '<paragraph>bar</paragraph>' );
  405. } );
  406. it( 'should navigate to the end position of the cell above when the direction is "up"', () => {
  407. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  408. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  409. [ '00', '01', '02' ],
  410. [ '10', '11', '12[]' ],
  411. [ '20', '21', '22' ]
  412. ] ) + '<paragraph>bar</paragraph>' );
  413. } );
  414. it( 'should select a whole table when the direction is "down"', () => {
  415. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  416. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>[' + modelTable( [
  417. [ '00', '01', '02' ],
  418. [ '10', '11', '12' ],
  419. [ '20', '21', '22' ]
  420. ] ) + ']<paragraph>bar</paragraph>' );
  421. } );
  422. it( 'should select a whole table when the direction is "right"', () => {
  423. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  424. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>[' + modelTable( [
  425. [ '00', '01', '02' ],
  426. [ '10', '11', '12' ],
  427. [ '20', '21', '22' ]
  428. ] ) + ']<paragraph>bar</paragraph>' );
  429. } );
  430. } );
  431. describe( 'from a cell in the first column (but not first row)', () => {
  432. let tableCell;
  433. beforeEach( () => {
  434. tableCell = modelRoot.getNodeByPath( [ 1, 1, 0 ] );
  435. } );
  436. it( 'should navigate to start position of the cell on the right when the direction is "right"', () => {
  437. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  438. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  439. [ '00', '01', '02' ],
  440. [ '10', '[]11', '12' ],
  441. [ '20', '21', '22' ]
  442. ] ) + '<paragraph>bar</paragraph>' );
  443. } );
  444. it( 'should navigate to the end position of the cell above when the direction is "up"', () => {
  445. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  446. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  447. [ '00[]', '01', '02' ],
  448. [ '10', '11', '12' ],
  449. [ '20', '21', '22' ]
  450. ] ) + '<paragraph>bar</paragraph>' );
  451. } );
  452. it( 'should navigate to the start position of the cell below when the direction is "down"', () => {
  453. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  454. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  455. [ '00', '01', '02' ],
  456. [ '10', '11', '12' ],
  457. [ '[]20', '21', '22' ]
  458. ] ) + '<paragraph>bar</paragraph>' );
  459. } );
  460. it( 'should navigate to the end position of the last cell in the previous row when the direction is "left"', () => {
  461. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  462. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  463. [ '00', '01', '02[]' ],
  464. [ '10', '11', '12' ],
  465. [ '20', '21', '22' ]
  466. ] ) + '<paragraph>bar</paragraph>' );
  467. } );
  468. } );
  469. describe( 'from a cell in the last column (but not the last row)', () => {
  470. let tableCell;
  471. beforeEach( () => {
  472. tableCell = modelRoot.getNodeByPath( [ 1, 1, 2 ] );
  473. } );
  474. it( 'should navigate to the end position of the cell on the left when the direction is "left"', () => {
  475. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  476. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  477. [ '00', '01', '02' ],
  478. [ '10', '11[]', '12' ],
  479. [ '20', '21', '22' ]
  480. ] ) + '<paragraph>bar</paragraph>' );
  481. } );
  482. it( 'should navigate to the end position the cell above when the direction is "up"', () => {
  483. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  484. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  485. [ '00', '01', '02[]' ],
  486. [ '10', '11', '12' ],
  487. [ '20', '21', '22' ]
  488. ] ) + '<paragraph>bar</paragraph>' );
  489. } );
  490. it( 'should navigate to the start position of the cell below when the direction is "down"', () => {
  491. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  492. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  493. [ '00', '01', '02' ],
  494. [ '10', '11', '12' ],
  495. [ '20', '21', '[]22' ]
  496. ] ) + '<paragraph>bar</paragraph>' );
  497. } );
  498. it( 'should navigate to the start position of the first cell in the next row when the direction is "right"', () => {
  499. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  500. assertEqualMarkup( getModelData( model ), '<paragraph>foo</paragraph>' + modelTable( [
  501. [ '00', '01', '02' ],
  502. [ '10', '11', '12' ],
  503. [ '[]20', '21', '22' ]
  504. ] ) + '<paragraph>bar</paragraph>' );
  505. } );
  506. } );
  507. } );
  508. describe( 'with col/row-spanned cells', () => {
  509. beforeEach( () => {
  510. // +----+----+----+----+----+
  511. // | 00 | 01 | 02 | 03 | 04 |
  512. // +----+----+----+----+----+
  513. // | 10 | 11 | 13 | 14 |
  514. // +----+ + +----+
  515. // | 20 | | | 24 |
  516. // +----+----+----+----+----+
  517. // | 30 | 31 | 33 | 34 |
  518. // +----+----+----+----+----+
  519. // | 40 | 41 | 42 | 43 | 44 |
  520. // +----+----+----+----+----+
  521. setModelData( model, modelTable( [
  522. [ '00', '01', '02', '03', '04' ],
  523. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  524. [ '20', '24' ],
  525. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  526. [ '40', '41', '42', '43', '44' ]
  527. ] ) );
  528. } );
  529. describe( 'when navigating to the right', () => {
  530. it( 'should navigate to the row-col-spanned cell when approaching from the upper-spanned row', () => {
  531. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 0 ] );
  532. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  533. assertEqualMarkup( getModelData( model ), modelTable( [
  534. [ '00', '01', '02', '03', '04' ],
  535. [ '10', { contents: '[]11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  536. [ '20', '24' ],
  537. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  538. [ '40', '41', '42', '43', '44' ]
  539. ] ) );
  540. } );
  541. it( 'should navigate to the row-col-spanned cell when approaching from the lower-spanned row', () => {
  542. const tableCell = modelRoot.getNodeByPath( [ 0, 2, 0 ] );
  543. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  544. assertEqualMarkup( getModelData( model ), modelTable( [
  545. [ '00', '01', '02', '03', '04' ],
  546. [ '10', { contents: '[]11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  547. [ '20', '24' ],
  548. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  549. [ '40', '41', '42', '43', '44' ]
  550. ] ) );
  551. } );
  552. it( 'should navigate to the row-spanned cell when approaching from the other row-spanned cell', () => {
  553. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  554. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  555. assertEqualMarkup( getModelData( model ), modelTable( [
  556. [ '00', '01', '02', '03', '04' ],
  557. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '[]13', rowspan: 2 }, '14' ],
  558. [ '20', '24' ],
  559. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  560. [ '40', '41', '42', '43', '44' ]
  561. ] ) );
  562. } );
  563. it( 'should navigate to the cell in the upper-spanned row when approaching from the row-spanned cell', () => {
  564. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13.
  565. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  566. assertEqualMarkup( getModelData( model ), modelTable( [
  567. [ '00', '01', '02', '03', '04' ],
  568. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '[]14' ],
  569. [ '20', '24' ],
  570. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  571. [ '40', '41', '42', '43', '44' ]
  572. ] ) );
  573. } );
  574. it( 'should navigate to the col-spanned cell', () => {
  575. const tableCell = modelRoot.getNodeByPath( [ 0, 3, 0 ] );
  576. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  577. assertEqualMarkup( getModelData( model ), modelTable( [
  578. [ '00', '01', '02', '03', '04' ],
  579. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  580. [ '20', '24' ],
  581. [ '30', { contents: '[]31', colspan: 2 }, '33', '34' ],
  582. [ '40', '41', '42', '43', '44' ]
  583. ] ) );
  584. } );
  585. it( 'should navigate from the col-spanned cell', () => {
  586. const tableCell = modelRoot.getNodeByPath( [ 0, 3, 1 ] );
  587. tableKeyboard._navigateFromCellInDirection( tableCell, 'right' );
  588. assertEqualMarkup( getModelData( model ), modelTable( [
  589. [ '00', '01', '02', '03', '04' ],
  590. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  591. [ '20', '24' ],
  592. [ '30', { contents: '31', colspan: 2 }, '[]33', '34' ],
  593. [ '40', '41', '42', '43', '44' ]
  594. ] ) );
  595. } );
  596. } );
  597. describe( 'when navigating to the left', () => {
  598. it( 'should navigate to the row-spanned cell when approaching from the upper-spanned row', () => {
  599. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 3 ] ); // Cell 14.
  600. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  601. assertEqualMarkup( getModelData( model ), modelTable( [
  602. [ '00', '01', '02', '03', '04' ],
  603. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13[]', rowspan: 2 }, '14' ],
  604. [ '20', '24' ],
  605. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  606. [ '40', '41', '42', '43', '44' ]
  607. ] ) );
  608. } );
  609. it( 'should navigate to the row-spanned cell when approaching from the lower-spanned row', () => {
  610. const tableCell = modelRoot.getNodeByPath( [ 0, 2, 1 ] ); // Cell 24.
  611. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  612. assertEqualMarkup( getModelData( model ), modelTable( [
  613. [ '00', '01', '02', '03', '04' ],
  614. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13[]', rowspan: 2 }, '14' ],
  615. [ '20', '24' ],
  616. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  617. [ '40', '41', '42', '43', '44' ]
  618. ] ) );
  619. } );
  620. it( 'should navigate to the row-spanned cell when approaching from the other row-spanned cell', () => {
  621. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13.
  622. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  623. assertEqualMarkup( getModelData( model ), modelTable( [
  624. [ '00', '01', '02', '03', '04' ],
  625. [ '10', { contents: '11[]', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  626. [ '20', '24' ],
  627. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  628. [ '40', '41', '42', '43', '44' ]
  629. ] ) );
  630. } );
  631. it( 'should navigate to the cell in the upper-spanned row when approaching from the row-spanned cell', () => {
  632. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] ); // Cell 11.
  633. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  634. assertEqualMarkup( getModelData( model ), modelTable( [
  635. [ '00', '01', '02', '03', '04' ],
  636. [ '10[]', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  637. [ '20', '24' ],
  638. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  639. [ '40', '41', '42', '43', '44' ]
  640. ] ) );
  641. } );
  642. it( 'should navigate to the col-spanned cell', () => {
  643. const tableCell = modelRoot.getNodeByPath( [ 0, 3, 2 ] ); // Cell 33.
  644. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  645. assertEqualMarkup( getModelData( model ), modelTable( [
  646. [ '00', '01', '02', '03', '04' ],
  647. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  648. [ '20', '24' ],
  649. [ '30', { contents: '31[]', colspan: 2 }, '33', '34' ],
  650. [ '40', '41', '42', '43', '44' ]
  651. ] ) );
  652. } );
  653. it( 'should navigate from the col-spanned cell', () => {
  654. const tableCell = modelRoot.getNodeByPath( [ 0, 3, 1 ] );
  655. tableKeyboard._navigateFromCellInDirection( tableCell, 'left' );
  656. assertEqualMarkup( getModelData( model ), modelTable( [
  657. [ '00', '01', '02', '03', '04' ],
  658. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  659. [ '20', '24' ],
  660. [ '30[]', { contents: '31', colspan: 2 }, '33', '34' ],
  661. [ '40', '41', '42', '43', '44' ]
  662. ] ) );
  663. } );
  664. } );
  665. describe( 'when navigating down', () => {
  666. it( 'should navigate to the row-col-spanned cell when approaching from the first spanned column', () => {
  667. const tableCell = modelRoot.getNodeByPath( [ 0, 0, 1 ] );
  668. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  669. assertEqualMarkup( getModelData( model ), modelTable( [
  670. [ '00', '01', '02', '03', '04' ],
  671. [ '10', { contents: '[]11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  672. [ '20', '24' ],
  673. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  674. [ '40', '41', '42', '43', '44' ]
  675. ] ) );
  676. } );
  677. it( 'should navigate to the row-col-spanned cell when approaching from the last spanned column', () => {
  678. const tableCell = modelRoot.getNodeByPath( [ 0, 0, 2 ] );
  679. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  680. assertEqualMarkup( getModelData( model ), modelTable( [
  681. [ '00', '01', '02', '03', '04' ],
  682. [ '10', { contents: '[]11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  683. [ '20', '24' ],
  684. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  685. [ '40', '41', '42', '43', '44' ]
  686. ] ) );
  687. } );
  688. it( 'should navigate to the row-spanned cell when approaching from the other col-spanned cell', () => {
  689. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  690. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  691. assertEqualMarkup( getModelData( model ), modelTable( [
  692. [ '00', '01', '02', '03', '04' ],
  693. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  694. [ '20', '24' ],
  695. [ '30', { contents: '[]31', colspan: 2 }, '33', '34' ],
  696. [ '40', '41', '42', '43', '44' ]
  697. ] ) );
  698. } );
  699. it( 'should navigate to the cell in the first spanned column when approaching from the col-spanned cell', () => {
  700. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] ); // Cell 11.
  701. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  702. assertEqualMarkup( getModelData( model ), modelTable( [
  703. [ '00', '01', '02', '03', '04' ],
  704. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  705. [ '20', '24' ],
  706. [ '30', { contents: '[]31', colspan: 2 }, '33', '34' ],
  707. [ '40', '41', '42', '43', '44' ]
  708. ] ) );
  709. } );
  710. it( 'should navigate to the row-spanned cell', () => {
  711. const tableCell = modelRoot.getNodeByPath( [ 0, 0, 3 ] );
  712. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  713. assertEqualMarkup( getModelData( model ), modelTable( [
  714. [ '00', '01', '02', '03', '04' ],
  715. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '[]13', rowspan: 2 }, '14' ],
  716. [ '20', '24' ],
  717. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  718. [ '40', '41', '42', '43', '44' ]
  719. ] ) );
  720. } );
  721. it( 'should navigate from the row-spanned cell', () => {
  722. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13.
  723. tableKeyboard._navigateFromCellInDirection( tableCell, 'down' );
  724. assertEqualMarkup( getModelData( model ), modelTable( [
  725. [ '00', '01', '02', '03', '04' ],
  726. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  727. [ '20', '24' ],
  728. [ '30', { contents: '31', colspan: 2 }, '[]33', '34' ],
  729. [ '40', '41', '42', '43', '44' ]
  730. ] ) );
  731. } );
  732. } );
  733. describe( 'when navigating up', () => {
  734. it( 'should navigate to the col-spanned cell when approaching from the first spanned column', () => {
  735. const tableCell = modelRoot.getNodeByPath( [ 0, 4, 1 ] );
  736. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  737. assertEqualMarkup( getModelData( model ), modelTable( [
  738. [ '00', '01', '02', '03', '04' ],
  739. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  740. [ '20', '24' ],
  741. [ '30', { contents: '31[]', colspan: 2 }, '33', '34' ],
  742. [ '40', '41', '42', '43', '44' ]
  743. ] ) );
  744. } );
  745. it( 'should navigate to the col-spanned cell when approaching from the last spanned column', () => {
  746. const tableCell = modelRoot.getNodeByPath( [ 0, 4, 2 ] );
  747. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  748. assertEqualMarkup( getModelData( model ), modelTable( [
  749. [ '00', '01', '02', '03', '04' ],
  750. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  751. [ '20', '24' ],
  752. [ '30', { contents: '31[]', colspan: 2 }, '33', '34' ],
  753. [ '40', '41', '42', '43', '44' ]
  754. ] ) );
  755. } );
  756. it( 'should navigate to the row-col-spanned cell when approaching from the other col-spanned cell', () => {
  757. const tableCell = modelRoot.getNodeByPath( [ 0, 3, 1 ] );
  758. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  759. assertEqualMarkup( getModelData( model ), modelTable( [
  760. [ '00', '01', '02', '03', '04' ],
  761. [ '10', { contents: '11[]', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  762. [ '20', '24' ],
  763. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  764. [ '40', '41', '42', '43', '44' ]
  765. ] ) );
  766. } );
  767. it( 'should navigate to the cell in the first spanned column when approaching from the col-spanned cell', () => {
  768. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  769. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  770. assertEqualMarkup( getModelData( model ), modelTable( [
  771. [ '00', '01[]', '02', '03', '04' ],
  772. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  773. [ '20', '24' ],
  774. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  775. [ '40', '41', '42', '43', '44' ]
  776. ] ) );
  777. } );
  778. it( 'should navigate to the row-spanned cell', () => {
  779. const tableCell = modelRoot.getNodeByPath( [ 0, 3, 2 ] ); // Cell 33.
  780. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  781. assertEqualMarkup( getModelData( model ), modelTable( [
  782. [ '00', '01', '02', '03', '04' ],
  783. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13[]', rowspan: 2 }, '14' ],
  784. [ '20', '24' ],
  785. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  786. [ '40', '41', '42', '43', '44' ]
  787. ] ) );
  788. } );
  789. it( 'should navigate from the row-spanned cell', () => {
  790. const tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] ); // Cell 13.
  791. tableKeyboard._navigateFromCellInDirection( tableCell, 'up' );
  792. assertEqualMarkup( getModelData( model ), modelTable( [
  793. [ '00', '01', '02', '03[]', '04' ],
  794. [ '10', { contents: '11', colspan: 2, rowspan: 2 }, { contents: '13', rowspan: 2 }, '14' ],
  795. [ '20', '24' ],
  796. [ '30', { contents: '31', colspan: 2 }, '33', '34' ],
  797. [ '40', '41', '42', '43', '44' ]
  798. ] ) );
  799. } );
  800. } );
  801. } );
  802. describe( 'when expanding selection', () => {
  803. beforeEach( () => {
  804. setModelData( model, modelTable( [
  805. [ '00[]', '01', '02' ],
  806. [ '10', '11', '12' ],
  807. [ '20', '21', '22' ]
  808. ] ) );
  809. } );
  810. describe( 'from the first table cell', () => {
  811. let tableCell;
  812. beforeEach( () => {
  813. tableCell = getTableCellsContainingSelection( selection )[ 0 ];
  814. } );
  815. it( 'should expand the selection to the cell on the right when the direction is "right"', () => {
  816. tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true );
  817. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  818. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  819. expect( selection.rangeCount ).to.equal( 2 );
  820. } );
  821. it( 'should expand the selection to the cell below when the direction is "down"', () => {
  822. tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true );
  823. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  824. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 0 ] ) );
  825. expect( selection.rangeCount ).to.equal( 2 );
  826. } );
  827. it( 'should select a whole table when the direction is "up"', () => {
  828. tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true );
  829. assertEqualMarkup( getModelData( model ), '[' + modelTable( [
  830. [ '00', '01', '02' ],
  831. [ '10', '11', '12' ],
  832. [ '20', '21', '22' ]
  833. ] ) + ']' );
  834. } );
  835. it( 'should select a whole table when the direction is "left"', () => {
  836. tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true );
  837. assertEqualMarkup( getModelData( model ), '[' + modelTable( [
  838. [ '00', '01', '02' ],
  839. [ '10', '11', '12' ],
  840. [ '20', '21', '22' ]
  841. ] ) + ']' );
  842. } );
  843. } );
  844. describe( 'from the last table cell', () => {
  845. let tableCell;
  846. beforeEach( () => {
  847. tableCell = modelRoot.getNodeByPath( [ 0, 2, 2 ] );
  848. tableSelection.setCellSelection( tableCell, tableCell );
  849. } );
  850. it( 'should expand the selection to the cell on the left when the direction is "left"', () => {
  851. tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true );
  852. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  853. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 1 ] ) );
  854. expect( selection.rangeCount ).to.equal( 2 );
  855. } );
  856. it( 'should expand the selection to the cell above when the direction is "up"', () => {
  857. tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true );
  858. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  859. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 2 ] ) );
  860. expect( selection.rangeCount ).to.equal( 2 );
  861. } );
  862. it( 'should select a whole table when the direction is "down"', () => {
  863. tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true );
  864. assertEqualMarkup( getModelData( model ), '[' + modelTable( [
  865. [ '00', '01', '02' ],
  866. [ '10', '11', '12' ],
  867. [ '20', '21', '22' ]
  868. ] ) + ']' );
  869. } );
  870. it( 'should select a whole table when the direction is "right"', () => {
  871. tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true );
  872. assertEqualMarkup( getModelData( model ), '[' + modelTable( [
  873. [ '00', '01', '02' ],
  874. [ '10', '11', '12' ],
  875. [ '20', '21', '22' ]
  876. ] ) + ']' );
  877. } );
  878. } );
  879. describe( 'from a cell in the first column (but not first row)', () => {
  880. let tableCell;
  881. beforeEach( () => {
  882. tableCell = modelRoot.getNodeByPath( [ 0, 1, 0 ] );
  883. tableSelection.setCellSelection( tableCell, tableCell );
  884. } );
  885. it( 'should expand the selection to the cell on the right when the direction is "right"', () => {
  886. tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true );
  887. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  888. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
  889. expect( selection.rangeCount ).to.equal( 2 );
  890. } );
  891. it( 'should expand the selection to the cell above when the direction is "up"', () => {
  892. tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true );
  893. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  894. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  895. expect( selection.rangeCount ).to.equal( 2 );
  896. } );
  897. it( 'should expand the selection to the cell below when the direction is "down"', () => {
  898. tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true );
  899. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  900. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 0 ] ) );
  901. expect( selection.rangeCount ).to.equal( 2 );
  902. } );
  903. it( 'should expand the selection to the cell above when the direction is "left"', () => {
  904. tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true );
  905. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  906. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 0 ] ) );
  907. expect( selection.rangeCount ).to.equal( 2 );
  908. } );
  909. } );
  910. describe( 'from a cell in the last column (but not the last row)', () => {
  911. let tableCell;
  912. beforeEach( () => {
  913. tableCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] );
  914. tableSelection.setCellSelection( tableCell, tableCell );
  915. } );
  916. it( 'should expand the selection to the cell on the left when the direction is "left"', () => {
  917. tableKeyboard._navigateFromCellInDirection( tableCell, 'left', true );
  918. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  919. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 1 ] ) );
  920. expect( selection.rangeCount ).to.equal( 2 );
  921. } );
  922. it( 'should expand the selection to the cell above when the direction is "up"', () => {
  923. tableKeyboard._navigateFromCellInDirection( tableCell, 'up', true );
  924. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  925. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 2 ] ) );
  926. expect( selection.rangeCount ).to.equal( 2 );
  927. } );
  928. it( 'should expand the selection to the cell below when the direction is "down"', () => {
  929. tableKeyboard._navigateFromCellInDirection( tableCell, 'down', true );
  930. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  931. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 2 ] ) );
  932. expect( selection.rangeCount ).to.equal( 2 );
  933. } );
  934. it( 'should expand the selection to the cell below when the direction is "right"', () => {
  935. tableKeyboard._navigateFromCellInDirection( tableCell, 'right', true );
  936. expect( tableSelection.getAnchorCell() ).to.equal( tableCell );
  937. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 2 ] ) );
  938. expect( selection.rangeCount ).to.equal( 2 );
  939. } );
  940. } );
  941. } );
  942. } );
  943. describe( 'with the table cells selected from outside', () => {
  944. describe( 'on a single table cell selected', () => {
  945. let anchorCell, focusCell;
  946. beforeEach( () => {
  947. setModelData( model, modelTable( [
  948. [ '00', '01', '02' ],
  949. [ '10', '11', '12' ],
  950. [ '20', '21', '22' ]
  951. ] ) );
  952. anchorCell = focusCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  953. tableSelection.setCellSelection( anchorCell, focusCell );
  954. } );
  955. describe( 'without shift pressed', () => {
  956. it( 'should move to the cell on the left', () => {
  957. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  958. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  959. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  960. assertEqualMarkup( getModelData( model ), modelTable( [
  961. [ '00', '01', '02' ],
  962. [ '10[]', '11', '12' ],
  963. [ '20', '21', '22' ]
  964. ] ) );
  965. } );
  966. it( 'should move to the cell on the right', () => {
  967. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  968. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  969. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  970. assertEqualMarkup( getModelData( model ), modelTable( [
  971. [ '00', '01', '02' ],
  972. [ '10', '11', '[]12' ],
  973. [ '20', '21', '22' ]
  974. ] ) );
  975. } );
  976. it( 'should move to the cell above the selection', () => {
  977. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  978. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  979. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  980. assertEqualMarkup( getModelData( model ), modelTable( [
  981. [ '00', '01[]', '02' ],
  982. [ '10', '11', '12' ],
  983. [ '20', '21', '22' ]
  984. ] ) );
  985. } );
  986. it( 'should move to the cell below the selection', () => {
  987. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  988. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  989. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  990. assertEqualMarkup( getModelData( model ), modelTable( [
  991. [ '00', '01', '02' ],
  992. [ '10', '11', '12' ],
  993. [ '20', '[]21', '22' ]
  994. ] ) );
  995. } );
  996. } );
  997. describe( 'with shift pressed', () => {
  998. beforeEach( () => {
  999. leftArrowDomEvtDataStub.shiftKey = true;
  1000. rightArrowDomEvtDataStub.shiftKey = true;
  1001. upArrowDomEvtDataStub.shiftKey = true;
  1002. downArrowDomEvtDataStub.shiftKey = true;
  1003. } );
  1004. it( 'should move to the cell below if TableSelection plugin is disabled', () => {
  1005. editor.plugins.get( 'TableSelection' ).forceDisabled();
  1006. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1007. assertEqualMarkup( getModelData( model ), modelTable( [
  1008. [ '00', '01', '02' ],
  1009. [ '10[]', '11', '12' ],
  1010. [ '20', '21', '22' ]
  1011. ] ) );
  1012. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1013. assertEqualMarkup( getModelData( model ), modelTable( [
  1014. [ '00', '01', '02' ],
  1015. [ '10', '11', '12' ],
  1016. [ '[]20', '21', '22' ]
  1017. ] ) );
  1018. expect( tableSelection.getAnchorCell() ).to.be.null;
  1019. expect( tableSelection.getFocusCell() ).to.be.null;
  1020. expect( selection.rangeCount ).to.equal( 1 );
  1021. } );
  1022. it( 'should expand the selection to the cell on the left', () => {
  1023. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1024. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1025. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1026. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1027. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 0 ] ) );
  1028. expect( selection.rangeCount ).to.equal( 2 );
  1029. } );
  1030. it( 'should expand the selection to the cell on the right', () => {
  1031. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1032. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1033. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1034. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1035. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 2 ] ) );
  1036. expect( selection.rangeCount ).to.equal( 2 );
  1037. } );
  1038. it( 'should expand the selection to the cell above the selection', () => {
  1039. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1040. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1041. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1042. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1043. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  1044. expect( selection.rangeCount ).to.equal( 2 );
  1045. } );
  1046. it( 'should expand the selection to the cell below the selection', () => {
  1047. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1048. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1049. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1050. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1051. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 1 ] ) );
  1052. expect( selection.rangeCount ).to.equal( 2 );
  1053. } );
  1054. } );
  1055. } );
  1056. describe( 'on multiple table cells selected vertically (the anchor cell above the focus cell)', () => {
  1057. let anchorCell, focusCell;
  1058. beforeEach( () => {
  1059. setModelData( model, modelTable( [
  1060. [ '00', '01', '02', '03' ],
  1061. [ '10', '11', '12', '13' ],
  1062. [ '20', '21', '22', '23' ],
  1063. [ '30', '31', '32', '33' ]
  1064. ] ) );
  1065. anchorCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  1066. focusCell = modelRoot.getNodeByPath( [ 0, 2, 1 ] );
  1067. tableSelection.setCellSelection( anchorCell, focusCell );
  1068. } );
  1069. describe( 'without shift pressed', () => {
  1070. it( 'should move to the cell on the top left of the selection', () => {
  1071. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1072. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1073. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1074. assertEqualMarkup( getModelData( model ), modelTable( [
  1075. [ '00', '01', '02', '03' ],
  1076. [ '10[]', '11', '12', '13' ],
  1077. [ '20', '21', '22', '23' ],
  1078. [ '30', '31', '32', '33' ]
  1079. ] ) );
  1080. } );
  1081. it( 'should move to the cell on the bottom right of the selection', () => {
  1082. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1083. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1084. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1085. assertEqualMarkup( getModelData( model ), modelTable( [
  1086. [ '00', '01', '02', '03' ],
  1087. [ '10', '11', '12', '13' ],
  1088. [ '20', '21', '[]22', '23' ],
  1089. [ '30', '31', '32', '33' ]
  1090. ] ) );
  1091. } );
  1092. it( 'should move to the cell above the selection', () => {
  1093. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1094. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1095. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1096. assertEqualMarkup( getModelData( model ), modelTable( [
  1097. [ '00', '01[]', '02', '03' ],
  1098. [ '10', '11', '12', '13' ],
  1099. [ '20', '21', '22', '23' ],
  1100. [ '30', '31', '32', '33' ]
  1101. ] ) );
  1102. } );
  1103. it( 'should move to the cell below the selection', () => {
  1104. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1105. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1106. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1107. assertEqualMarkup( getModelData( model ), modelTable( [
  1108. [ '00', '01', '02', '03' ],
  1109. [ '10', '11', '12', '13' ],
  1110. [ '20', '21', '22', '23' ],
  1111. [ '30', '[]31', '32', '33' ]
  1112. ] ) );
  1113. } );
  1114. } );
  1115. describe( 'with shift pressed', () => {
  1116. beforeEach( () => {
  1117. leftArrowDomEvtDataStub.shiftKey = true;
  1118. rightArrowDomEvtDataStub.shiftKey = true;
  1119. upArrowDomEvtDataStub.shiftKey = true;
  1120. downArrowDomEvtDataStub.shiftKey = true;
  1121. } );
  1122. it( 'should expand the selection to the cell on the left from the focus cell', () => {
  1123. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1124. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1125. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1126. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1127. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 0 ] ) );
  1128. expect( selection.rangeCount ).to.equal( 4 );
  1129. } );
  1130. it( 'should expand the selection to the cell on the right from the focus cell', () => {
  1131. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1132. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1133. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1134. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1135. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 2 ] ) );
  1136. expect( selection.rangeCount ).to.equal( 4 );
  1137. } );
  1138. it( 'should shrink the selection to the anchor cell', () => {
  1139. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1140. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1141. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1142. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1143. expect( tableSelection.getFocusCell() ).to.equal( anchorCell );
  1144. expect( selection.rangeCount ).to.equal( 1 );
  1145. } );
  1146. it( 'should expand the selection to the cell below the focus cell', () => {
  1147. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1148. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1149. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1150. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1151. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 3, 1 ] ) );
  1152. expect( selection.rangeCount ).to.equal( 3 );
  1153. } );
  1154. } );
  1155. } );
  1156. describe( 'on multiple table cells selected vertically (the anchor cell below the focus cell)', () => {
  1157. let anchorCell, focusCell;
  1158. beforeEach( () => {
  1159. setModelData( model, modelTable( [
  1160. [ '00', '01', '02', '03' ],
  1161. [ '10', '11', '12', '13' ],
  1162. [ '20', '21', '22', '23' ],
  1163. [ '30', '31', '32', '33' ]
  1164. ] ) );
  1165. anchorCell = modelRoot.getNodeByPath( [ 0, 2, 1 ] );
  1166. focusCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  1167. tableSelection.setCellSelection( anchorCell, focusCell );
  1168. } );
  1169. describe( 'without shift pressed', () => {
  1170. it( 'should move to the cell on the top left of the selection', () => {
  1171. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1172. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1173. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1174. assertEqualMarkup( getModelData( model ), modelTable( [
  1175. [ '00', '01', '02', '03' ],
  1176. [ '10[]', '11', '12', '13' ],
  1177. [ '20', '21', '22', '23' ],
  1178. [ '30', '31', '32', '33' ]
  1179. ] ) );
  1180. } );
  1181. it( 'should move to the cell on the bottom right of the selection', () => {
  1182. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1183. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1184. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1185. assertEqualMarkup( getModelData( model ), modelTable( [
  1186. [ '00', '01', '02', '03' ],
  1187. [ '10', '11', '12', '13' ],
  1188. [ '20', '21', '[]22', '23' ],
  1189. [ '30', '31', '32', '33' ]
  1190. ] ) );
  1191. } );
  1192. it( 'should move to the cell above the selection', () => {
  1193. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1194. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1195. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1196. assertEqualMarkup( getModelData( model ), modelTable( [
  1197. [ '00', '01[]', '02', '03' ],
  1198. [ '10', '11', '12', '13' ],
  1199. [ '20', '21', '22', '23' ],
  1200. [ '30', '31', '32', '33' ]
  1201. ] ) );
  1202. } );
  1203. it( 'should move to the cell below the selection', () => {
  1204. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1205. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1206. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1207. assertEqualMarkup( getModelData( model ), modelTable( [
  1208. [ '00', '01', '02', '03' ],
  1209. [ '10', '11', '12', '13' ],
  1210. [ '20', '21', '22', '23' ],
  1211. [ '30', '[]31', '32', '33' ]
  1212. ] ) );
  1213. } );
  1214. } );
  1215. describe( 'with shift pressed', () => {
  1216. beforeEach( () => {
  1217. leftArrowDomEvtDataStub.shiftKey = true;
  1218. rightArrowDomEvtDataStub.shiftKey = true;
  1219. upArrowDomEvtDataStub.shiftKey = true;
  1220. downArrowDomEvtDataStub.shiftKey = true;
  1221. } );
  1222. it( 'should expand the selection to the cell on the left from the focus cell', () => {
  1223. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1224. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1225. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1226. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1227. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 0 ] ) );
  1228. expect( selection.rangeCount ).to.equal( 4 );
  1229. } );
  1230. it( 'should expand the selection to the cell on the right from the focus cell', () => {
  1231. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1232. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1233. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1234. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1235. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 2 ] ) );
  1236. expect( selection.rangeCount ).to.equal( 4 );
  1237. } );
  1238. it( 'should shrink the selection to the anchor cell', () => {
  1239. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1240. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1241. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1242. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1243. expect( tableSelection.getFocusCell() ).to.equal( anchorCell );
  1244. expect( selection.rangeCount ).to.equal( 1 );
  1245. } );
  1246. it( 'should expand the selection to the cell below the focus cell', () => {
  1247. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1248. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1249. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1250. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1251. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 1 ] ) );
  1252. expect( selection.rangeCount ).to.equal( 3 );
  1253. } );
  1254. } );
  1255. } );
  1256. describe( 'on multiple table cell selected horizontally (the anchor cell is to the left of the focus cell ', () => {
  1257. let anchorCell, focusCell;
  1258. beforeEach( () => {
  1259. setModelData( model, modelTable( [
  1260. [ '00', '01', '02', '03' ],
  1261. [ '10', '11', '12', '13' ],
  1262. [ '20', '21', '22', '23' ],
  1263. [ '30', '31', '32', '33' ]
  1264. ] ) );
  1265. anchorCell = modelRoot.getNodeByPath( [ 0, 1, 1 ] );
  1266. focusCell = modelRoot.getNodeByPath( [ 0, 1, 2 ] );
  1267. tableSelection.setCellSelection( anchorCell, focusCell );
  1268. } );
  1269. describe( 'without shift pressed', () => {
  1270. it( 'should move to the cell on the top left of the selection', () => {
  1271. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1272. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1273. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1274. assertEqualMarkup( getModelData( model ), modelTable( [
  1275. [ '00', '01', '02', '03' ],
  1276. [ '10[]', '11', '12', '13' ],
  1277. [ '20', '21', '22', '23' ],
  1278. [ '30', '31', '32', '33' ]
  1279. ] ) );
  1280. } );
  1281. it( 'should move to the cell on the bottom right of the selection', () => {
  1282. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1283. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1284. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1285. assertEqualMarkup( getModelData( model ), modelTable( [
  1286. [ '00', '01', '02', '03' ],
  1287. [ '10', '11', '12', '[]13' ],
  1288. [ '20', '21', '22', '23' ],
  1289. [ '30', '31', '32', '33' ]
  1290. ] ) );
  1291. } );
  1292. it( 'should move to the cell above the selection', () => {
  1293. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1294. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1295. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1296. assertEqualMarkup( getModelData( model ), modelTable( [
  1297. [ '00', '01[]', '02', '03' ],
  1298. [ '10', '11', '12', '13' ],
  1299. [ '20', '21', '22', '23' ],
  1300. [ '30', '31', '32', '33' ]
  1301. ] ) );
  1302. } );
  1303. it( 'should move to the cell below the selection', () => {
  1304. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1305. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1306. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1307. assertEqualMarkup( getModelData( model ), modelTable( [
  1308. [ '00', '01', '02', '03' ],
  1309. [ '10', '11', '12', '13' ],
  1310. [ '20', '21', '[]22', '23' ],
  1311. [ '30', '31', '32', '33' ]
  1312. ] ) );
  1313. } );
  1314. } );
  1315. describe( 'with shift pressed', () => {
  1316. beforeEach( () => {
  1317. leftArrowDomEvtDataStub.shiftKey = true;
  1318. rightArrowDomEvtDataStub.shiftKey = true;
  1319. upArrowDomEvtDataStub.shiftKey = true;
  1320. downArrowDomEvtDataStub.shiftKey = true;
  1321. } );
  1322. it( 'should expand the selection to the cell above the focus cell', () => {
  1323. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1324. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1325. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1326. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1327. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 0, 2 ] ) );
  1328. expect( selection.rangeCount ).to.equal( 4 );
  1329. } );
  1330. it( 'should expand the selection to the cell below the focus cell', () => {
  1331. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1332. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1333. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1334. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1335. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 2, 2 ] ) );
  1336. expect( selection.rangeCount ).to.equal( 4 );
  1337. } );
  1338. it( 'should shrink the selection to the anchor cell', () => {
  1339. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1340. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1341. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1342. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1343. expect( tableSelection.getFocusCell() ).to.equal( anchorCell );
  1344. expect( selection.rangeCount ).to.equal( 1 );
  1345. } );
  1346. it( 'should expand the selection to the cell on the right to the focus cell', () => {
  1347. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1348. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1349. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1350. expect( tableSelection.getAnchorCell() ).to.equal( anchorCell );
  1351. expect( tableSelection.getFocusCell() ).to.equal( modelRoot.getNodeByPath( [ 0, 1, 3 ] ) );
  1352. expect( selection.rangeCount ).to.equal( 3 );
  1353. } );
  1354. } );
  1355. } );
  1356. describe( 'on multiple table cell selected diagonally', () => {
  1357. beforeEach( () => {
  1358. setModelData( model, modelTable( [
  1359. [ '00', '01', '02', '03' ],
  1360. [ '10', '11', '12', '13' ],
  1361. [ '20', '21', '22', '23' ],
  1362. [ '30', '31', '32', '33' ]
  1363. ] ) );
  1364. tableSelection.setCellSelection(
  1365. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1366. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  1367. );
  1368. } );
  1369. it( 'should move to the cell on the top left of selection', () => {
  1370. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1371. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1372. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1373. assertEqualMarkup( getModelData( model ), modelTable( [
  1374. [ '00', '01', '02', '03' ],
  1375. [ '10[]', '11', '12', '13' ],
  1376. [ '20', '21', '22', '23' ],
  1377. [ '30', '31', '32', '33' ]
  1378. ] ) );
  1379. } );
  1380. it( 'should move to the cell on the bottom right of selection', () => {
  1381. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1382. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1383. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1384. assertEqualMarkup( getModelData( model ), modelTable( [
  1385. [ '00', '01', '02', '03' ],
  1386. [ '10', '11', '12', '13' ],
  1387. [ '20', '21', '22', '[]23' ],
  1388. [ '30', '31', '32', '33' ]
  1389. ] ) );
  1390. } );
  1391. it( 'should move to the cell above selection', () => {
  1392. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1393. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1394. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1395. assertEqualMarkup( getModelData( model ), modelTable( [
  1396. [ '00', '01[]', '02', '03' ],
  1397. [ '10', '11', '12', '13' ],
  1398. [ '20', '21', '22', '23' ],
  1399. [ '30', '31', '32', '33' ]
  1400. ] ) );
  1401. } );
  1402. it( 'should move to the cell below selection', () => {
  1403. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1404. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1405. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1406. assertEqualMarkup( getModelData( model ), modelTable( [
  1407. [ '00', '01', '02', '03' ],
  1408. [ '10', '11', '12', '13' ],
  1409. [ '20', '21', '22', '23' ],
  1410. [ '30', '31', '[]32', '33' ]
  1411. ] ) );
  1412. } );
  1413. } );
  1414. } );
  1415. describe( 'with the selection inside a table cell', () => {
  1416. describe( 'with the selection at the boundary of a cell', () => {
  1417. describe( 'simple cell text content', () => {
  1418. it( 'should navigate to the cell on the left', () => {
  1419. setModelData( model, modelTable( [
  1420. [ '00', '01', '02' ],
  1421. [ '10', '[]11', '12' ],
  1422. [ '20', '21', '22' ]
  1423. ] ) );
  1424. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1425. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1426. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1427. assertEqualMarkup( getModelData( model ), modelTable( [
  1428. [ '00', '01', '02' ],
  1429. [ '10[]', '11', '12' ],
  1430. [ '20', '21', '22' ]
  1431. ] ) );
  1432. } );
  1433. it( 'should navigate to the cell on the right', () => {
  1434. setModelData( model, modelTable( [
  1435. [ '00', '01', '02' ],
  1436. [ '10', '11[]', '12' ],
  1437. [ '20', '21', '22' ]
  1438. ] ) );
  1439. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1440. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1441. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1442. assertEqualMarkup( getModelData( model ), modelTable( [
  1443. [ '00', '01', '02' ],
  1444. [ '10', '11', '[]12' ],
  1445. [ '20', '21', '22' ]
  1446. ] ) );
  1447. } );
  1448. it( 'should navigate to the cell above', () => {
  1449. setModelData( model, modelTable( [
  1450. [ '00', '01', '02' ],
  1451. [ '10', '[]11', '12' ],
  1452. [ '20', '21', '22' ]
  1453. ] ) );
  1454. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1455. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1456. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1457. assertEqualMarkup( getModelData( model ), modelTable( [
  1458. [ '00', '01[]', '02' ],
  1459. [ '10', '11', '12' ],
  1460. [ '20', '21', '22' ]
  1461. ] ) );
  1462. } );
  1463. it( 'should navigate to the cell below', () => {
  1464. setModelData( model, modelTable( [
  1465. [ '00', '01', '02' ],
  1466. [ '10', '11[]', '12' ],
  1467. [ '20', '21', '22' ]
  1468. ] ) );
  1469. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1470. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1471. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1472. assertEqualMarkup( getModelData( model ), modelTable( [
  1473. [ '00', '01', '02' ],
  1474. [ '10', '11', '12' ],
  1475. [ '20', '[]21', '22' ]
  1476. ] ) );
  1477. } );
  1478. } );
  1479. describe( 'multiple paragraphs in the cell content', () => {
  1480. it( 'should navigate to the cell on the left', () => {
  1481. setModelData( model, modelTable( [
  1482. [ '00', '01', '02' ],
  1483. [ '10', '<paragraph>[]11</paragraph><paragraph>x</paragraph>', '12' ],
  1484. [ '20', '21', '22' ]
  1485. ] ) );
  1486. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1487. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1488. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1489. assertEqualMarkup( getModelData( model ), modelTable( [
  1490. [ '00', '01', '02' ],
  1491. [ '10[]', '<paragraph>11</paragraph><paragraph>x</paragraph>', '12' ],
  1492. [ '20', '21', '22' ]
  1493. ] ) );
  1494. } );
  1495. it( 'should navigate to the cell on the right', () => {
  1496. setModelData( model, modelTable( [
  1497. [ '00', '01', '02' ],
  1498. [ '10', '<paragraph>11</paragraph><paragraph>x[]</paragraph>', '12' ],
  1499. [ '20', '21', '22' ]
  1500. ] ) );
  1501. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1502. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1503. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1504. assertEqualMarkup( getModelData( model ), modelTable( [
  1505. [ '00', '01', '02' ],
  1506. [ '10', '<paragraph>11</paragraph><paragraph>x</paragraph>', '[]12' ],
  1507. [ '20', '21', '22' ]
  1508. ] ) );
  1509. } );
  1510. it( 'should navigate to the cell above', () => {
  1511. setModelData( model, modelTable( [
  1512. [ '00', '01', '02' ],
  1513. [ '10', '<paragraph>[]11</paragraph><paragraph>x</paragraph>', '12' ],
  1514. [ '20', '21', '22' ]
  1515. ] ) );
  1516. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1517. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1518. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1519. assertEqualMarkup( getModelData( model ), modelTable( [
  1520. [ '00', '01[]', '02' ],
  1521. [ '10', '<paragraph>11</paragraph><paragraph>x</paragraph>', '12' ],
  1522. [ '20', '21', '22' ]
  1523. ] ) );
  1524. } );
  1525. it( 'should navigate to the cell below', () => {
  1526. setModelData( model, modelTable( [
  1527. [ '00', '01', '02' ],
  1528. [ '10', '<paragraph>11</paragraph><paragraph>x[]</paragraph>', '12' ],
  1529. [ '20', '21', '22' ]
  1530. ] ) );
  1531. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1532. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1533. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1534. assertEqualMarkup( getModelData( model ), modelTable( [
  1535. [ '00', '01', '02' ],
  1536. [ '10', '<paragraph>11</paragraph><paragraph>x</paragraph>', '12' ],
  1537. [ '20', '[]21', '22' ]
  1538. ] ) );
  1539. } );
  1540. } );
  1541. describe( 'image widget with caption as only cell content', () => {
  1542. it( 'should navigate to the cell on the left', () => {
  1543. setModelData( model, modelTable( [
  1544. [ '00', '01', '02' ],
  1545. [ '10', `<image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  1546. [ '20', '21', '22' ]
  1547. ] ) );
  1548. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1549. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1550. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1551. assertEqualMarkup( getModelData( model ), modelTable( [
  1552. [ '00', '01', '02' ],
  1553. [ '10[]', `<image src="${ imageUrl }"><caption>11</caption></image>`, '12' ],
  1554. [ '20', '21', '22' ]
  1555. ] ) );
  1556. } );
  1557. it( 'should navigate to the cell on the right', () => {
  1558. setModelData( model, modelTable( [
  1559. [ '00', '01', '02' ],
  1560. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image>`, '12' ],
  1561. [ '20', '21', '22' ]
  1562. ] ) );
  1563. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1564. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1565. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1566. assertEqualMarkup( getModelData( model ), modelTable( [
  1567. [ '00', '01', '02' ],
  1568. [ '10', `<image src="${ imageUrl }"><caption>11</caption></image>`, '[]12' ],
  1569. [ '20', '21', '22' ]
  1570. ] ) );
  1571. } );
  1572. it( 'should navigate to the cell above', () => {
  1573. setModelData( model, modelTable( [
  1574. [ '00', '01', '02' ],
  1575. [ '10', `<image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  1576. [ '20', '21', '22' ]
  1577. ] ) );
  1578. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1579. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1580. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1581. assertEqualMarkup( getModelData( model ), modelTable( [
  1582. [ '00', '01[]', '02' ],
  1583. [ '10', `<image src="${ imageUrl }"><caption>11</caption></image>`, '12' ],
  1584. [ '20', '21', '22' ]
  1585. ] ) );
  1586. } );
  1587. it( 'should navigate to the cell below', () => {
  1588. setModelData( model, modelTable( [
  1589. [ '00', '01', '02' ],
  1590. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image>`, '12' ],
  1591. [ '20', '21', '22' ]
  1592. ] ) );
  1593. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1594. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1595. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1596. assertEqualMarkup( getModelData( model ), modelTable( [
  1597. [ '00', '01', '02' ],
  1598. [ '10', `<image src="${ imageUrl }"><caption>11</caption></image>`, '12' ],
  1599. [ '20', '[]21', '22' ]
  1600. ] ) );
  1601. } );
  1602. } );
  1603. describe( 'horizontal line as only cell content (widget without $text positions)', () => {
  1604. beforeEach( () => {
  1605. setModelData( model, modelTable( [
  1606. [ '00', '01', '02' ],
  1607. [ '10', '[<horizontalLine></horizontalLine>]', '12' ],
  1608. [ '20', '21', '22' ]
  1609. ] ) );
  1610. } );
  1611. it( 'should navigate to the cell on the left', () => {
  1612. // Twice because of fake caret next to widget.
  1613. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1614. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1615. sinon.assert.called( leftArrowDomEvtDataStub.preventDefault );
  1616. sinon.assert.called( leftArrowDomEvtDataStub.stopPropagation );
  1617. assertEqualMarkup( getModelData( model ), modelTable( [
  1618. [ '00', '01', '02' ],
  1619. [ '10[]', '<horizontalLine></horizontalLine>', '12' ],
  1620. [ '20', '21', '22' ]
  1621. ] ) );
  1622. } );
  1623. it( 'should navigate to the cell on the right', () => {
  1624. // Twice because of fake caret next to widget.
  1625. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1626. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1627. sinon.assert.called( rightArrowDomEvtDataStub.preventDefault );
  1628. sinon.assert.called( rightArrowDomEvtDataStub.stopPropagation );
  1629. assertEqualMarkup( getModelData( model ), modelTable( [
  1630. [ '00', '01', '02' ],
  1631. [ '10', '<horizontalLine></horizontalLine>', '[]12' ],
  1632. [ '20', '21', '22' ]
  1633. ] ) );
  1634. } );
  1635. it( 'should navigate to the cell above', () => {
  1636. // Twice because of fake caret next to widget.
  1637. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1638. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1639. sinon.assert.called( upArrowDomEvtDataStub.preventDefault );
  1640. sinon.assert.called( upArrowDomEvtDataStub.stopPropagation );
  1641. assertEqualMarkup( getModelData( model ), modelTable( [
  1642. [ '00', '01[]', '02' ],
  1643. [ '10', '<horizontalLine></horizontalLine>', '12' ],
  1644. [ '20', '21', '22' ]
  1645. ] ) );
  1646. } );
  1647. it( 'should navigate to the cell below', () => {
  1648. // Twice because of fake caret next to widget.
  1649. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1650. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1651. sinon.assert.called( downArrowDomEvtDataStub.preventDefault );
  1652. sinon.assert.called( downArrowDomEvtDataStub.stopPropagation );
  1653. assertEqualMarkup( getModelData( model ), modelTable( [
  1654. [ '00', '01', '02' ],
  1655. [ '10', '<horizontalLine></horizontalLine>', '12' ],
  1656. [ '20', '[]21', '22' ]
  1657. ] ) );
  1658. } );
  1659. } );
  1660. describe( 'two horizontal lines as only cell content (widget without $text positions)', () => {
  1661. it( 'should navigate to the cell on the left', () => {
  1662. setModelData( model, modelTable( [
  1663. [ '00', '01', '02' ],
  1664. [ '10', '[<horizontalLine></horizontalLine>]<horizontalLine></horizontalLine>', '12' ],
  1665. [ '20', '21', '22' ]
  1666. ] ) );
  1667. // Twice because of fake caret next to widget.
  1668. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1669. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1670. sinon.assert.called( leftArrowDomEvtDataStub.preventDefault );
  1671. sinon.assert.called( leftArrowDomEvtDataStub.stopPropagation );
  1672. assertEqualMarkup( getModelData( model ), modelTable( [
  1673. [ '00', '01', '02' ],
  1674. [ '10[]', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '12' ],
  1675. [ '20', '21', '22' ]
  1676. ] ) );
  1677. } );
  1678. it( 'should navigate to the cell on the right', () => {
  1679. setModelData( model, modelTable( [
  1680. [ '00', '01', '02' ],
  1681. [ '10', '<horizontalLine></horizontalLine>[<horizontalLine></horizontalLine>]', '12' ],
  1682. [ '20', '21', '22' ]
  1683. ] ) );
  1684. // Twice because of fake caret next to widget.
  1685. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1686. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1687. sinon.assert.called( rightArrowDomEvtDataStub.preventDefault );
  1688. sinon.assert.called( rightArrowDomEvtDataStub.stopPropagation );
  1689. assertEqualMarkup( getModelData( model ), modelTable( [
  1690. [ '00', '01', '02' ],
  1691. [ '10', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '[]12' ],
  1692. [ '20', '21', '22' ]
  1693. ] ) );
  1694. } );
  1695. it( 'should navigate to the cell above', () => {
  1696. setModelData( model, modelTable( [
  1697. [ '00', '01', '02' ],
  1698. [ '10', '[<horizontalLine></horizontalLine>]<horizontalLine></horizontalLine>', '12' ],
  1699. [ '20', '21', '22' ]
  1700. ] ) );
  1701. // Twice because of fake caret next to widget.
  1702. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1703. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1704. sinon.assert.called( upArrowDomEvtDataStub.preventDefault );
  1705. sinon.assert.called( upArrowDomEvtDataStub.stopPropagation );
  1706. assertEqualMarkup( getModelData( model ), modelTable( [
  1707. [ '00', '01[]', '02' ],
  1708. [ '10', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '12' ],
  1709. [ '20', '21', '22' ]
  1710. ] ) );
  1711. } );
  1712. it( 'should navigate to the cell below', () => {
  1713. setModelData( model, modelTable( [
  1714. [ '00', '01', '02' ],
  1715. [ '10', '<horizontalLine></horizontalLine>[<horizontalLine></horizontalLine>]', '12' ],
  1716. [ '20', '21', '22' ]
  1717. ] ) );
  1718. // Twice because of fake caret next to widget.
  1719. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1720. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1721. sinon.assert.called( downArrowDomEvtDataStub.preventDefault );
  1722. sinon.assert.called( downArrowDomEvtDataStub.stopPropagation );
  1723. assertEqualMarkup( getModelData( model ), modelTable( [
  1724. [ '00', '01', '02' ],
  1725. [ '10', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '12' ],
  1726. [ '20', '[]21', '22' ]
  1727. ] ) );
  1728. } );
  1729. } );
  1730. } );
  1731. describe( 'with selection not at the boundary of a cell', () => {
  1732. let styleElement;
  1733. beforeEach( async () => {
  1734. styleElement = global.document.createElement( 'style' );
  1735. styleElement.type = 'text/css';
  1736. styleElement.appendChild( global.document.createTextNode(
  1737. `
  1738. * {
  1739. font-size: 12px !important;
  1740. font-family: serif !important;
  1741. margin: 0 !important;
  1742. padding: 0 !important;
  1743. border: 0 !important
  1744. }
  1745. td { width: 30px !important; }
  1746. tr:nth-child(2) td:nth-child(2) { width: 300px !important; }
  1747. `
  1748. ) );
  1749. global.document.querySelector( 'head' ).appendChild( styleElement );
  1750. // The editing view must be focused because otherwise in Chrome the DOM selection will not contain
  1751. // any ranges and jumpOverUiElement will crash (for the right arrow when shift is pressed).
  1752. editor.editing.view.focus();
  1753. } );
  1754. afterEach( async () => {
  1755. styleElement.remove();
  1756. } );
  1757. describe( 'simple cell text content', () => {
  1758. it( 'should not navigate to the cell on the left', () => {
  1759. setModelData( model, modelTable( [
  1760. [ '00', '01', '02' ],
  1761. [ '10', '1[]1', '12' ],
  1762. [ '20', '21', '22' ]
  1763. ] ) );
  1764. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1765. sinon.assert.notCalled( leftArrowDomEvtDataStub.preventDefault );
  1766. sinon.assert.notCalled( leftArrowDomEvtDataStub.stopPropagation );
  1767. } );
  1768. it( 'should not navigate to the cell on the right', () => {
  1769. setModelData( model, modelTable( [
  1770. [ '00', '01', '02' ],
  1771. [ '10', '1[]1', '12' ],
  1772. [ '20', '21', '22' ]
  1773. ] ) );
  1774. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1775. sinon.assert.notCalled( rightArrowDomEvtDataStub.preventDefault );
  1776. sinon.assert.notCalled( rightArrowDomEvtDataStub.stopPropagation );
  1777. } );
  1778. it( 'should not navigate to the cell above', () => {
  1779. setModelData( model, modelTable( [
  1780. [ '00', '01', '02' ],
  1781. [ '10', '1[]1', '12' ],
  1782. [ '20', '21', '22' ]
  1783. ] ) );
  1784. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1785. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1786. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1787. assertEqualMarkup( getModelData( model ), modelTable( [
  1788. [ '00', '01', '02' ],
  1789. [ '10', '[]11', '12' ],
  1790. [ '20', '21', '22' ]
  1791. ] ) );
  1792. } );
  1793. it( 'should not navigate to the cell below', () => {
  1794. setModelData( model, modelTable( [
  1795. [ '00', '01', '02' ],
  1796. [ '10', '1[]1', '12' ],
  1797. [ '20', '21', '22' ]
  1798. ] ) );
  1799. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1800. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1801. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1802. assertEqualMarkup( getModelData( model ), modelTable( [
  1803. [ '00', '01', '02' ],
  1804. [ '10', '11[]', '12' ],
  1805. [ '20', '21', '22' ]
  1806. ] ) );
  1807. } );
  1808. describe( 'when shift key is pressed', () => {
  1809. beforeEach( () => {
  1810. setModelData( model, modelTable( [
  1811. [ '00', '01', '02' ],
  1812. [ '10', '1[]1', '12' ],
  1813. [ '20', '21', '22' ]
  1814. ] ) );
  1815. leftArrowDomEvtDataStub.shiftKey = true;
  1816. rightArrowDomEvtDataStub.shiftKey = true;
  1817. upArrowDomEvtDataStub.shiftKey = true;
  1818. downArrowDomEvtDataStub.shiftKey = true;
  1819. } );
  1820. it( 'should not prevent default browser behavior for the left arrow pressed with shift', () => {
  1821. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1822. sinon.assert.notCalled( leftArrowDomEvtDataStub.preventDefault );
  1823. sinon.assert.notCalled( leftArrowDomEvtDataStub.stopPropagation );
  1824. } );
  1825. it( 'should not prevent default browser behavior for the right arrow pressed with shift', () => {
  1826. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1827. sinon.assert.notCalled( rightArrowDomEvtDataStub.preventDefault );
  1828. sinon.assert.notCalled( rightArrowDomEvtDataStub.stopPropagation );
  1829. } );
  1830. it( 'should expand selection to the beginning of the cell content', () => {
  1831. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1832. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1833. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1834. assertEqualMarkup( getModelData( model ), modelTable( [
  1835. [ '00', '01', '02' ],
  1836. [ '10', '[1]1', '12' ],
  1837. [ '20', '21', '22' ]
  1838. ] ) );
  1839. } );
  1840. it( 'should expand selection to the end of the cell content', () => {
  1841. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1842. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1843. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1844. assertEqualMarkup( getModelData( model ), modelTable( [
  1845. [ '00', '01', '02' ],
  1846. [ '10', '1[1]', '12' ],
  1847. [ '20', '21', '22' ]
  1848. ] ) );
  1849. } );
  1850. } );
  1851. } );
  1852. describe( 'selection inside paragraph', () => {
  1853. const text = new Array( 20 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  1854. it( 'should not navigate if caret is in the middle line of a text', () => {
  1855. setModelData( model, modelTable( [
  1856. [ '00', '01', '02' ],
  1857. [ '10', text + '[] ' + text, '12' ],
  1858. [ '20', '21', '22' ]
  1859. ] ) );
  1860. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1861. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  1862. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  1863. } );
  1864. it( 'should move caret to beginning of cell content if caret is in the first line of a text', () => {
  1865. setModelData( model, modelTable( [
  1866. [ '00', '01', '02' ],
  1867. [ '10', 'word[] word' + text, '12' ],
  1868. [ '20', '21', '22' ]
  1869. ] ) );
  1870. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1871. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1872. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1873. assertEqualMarkup( getModelData( model ), modelTable( [
  1874. [ '00', '01', '02' ],
  1875. [ '10', '[]word word' + text, '12' ],
  1876. [ '20', '21', '22' ]
  1877. ] ) );
  1878. } );
  1879. it( 'should move caret to end of cell content if caret is in the last line of a text', () => {
  1880. setModelData( model, modelTable( [
  1881. [ '00', '01', '02' ],
  1882. [ '10', text + 'word[] word', '12' ],
  1883. [ '20', '21', '22' ]
  1884. ] ) );
  1885. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1886. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1887. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1888. assertEqualMarkup( getModelData( model ), modelTable( [
  1889. [ '00', '01', '02' ],
  1890. [ '10', text + 'word word[]', '12' ],
  1891. [ '20', '21', '22' ]
  1892. ] ) );
  1893. } );
  1894. describe( 'when shift key is pressed', () => {
  1895. beforeEach( () => {
  1896. upArrowDomEvtDataStub.shiftKey = true;
  1897. downArrowDomEvtDataStub.shiftKey = true;
  1898. } );
  1899. it( 'should not prevent default browser behavior for the up arrow in the middle lines of the cell text', () => {
  1900. setModelData( model, modelTable( [
  1901. [ '00', '01', '02' ],
  1902. [ '10', text + '[] ' + text, '12' ],
  1903. [ '20', '21', '22' ]
  1904. ] ) );
  1905. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1906. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  1907. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  1908. } );
  1909. it( 'should not prevent default browser behavior for the down arrow in the middle lines of cell text', () => {
  1910. setModelData( model, modelTable( [
  1911. [ '00', '01', '02' ],
  1912. [ '10', text + '[] ' + text, '12' ],
  1913. [ '20', '21', '22' ]
  1914. ] ) );
  1915. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1916. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  1917. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  1918. } );
  1919. it( 'should expand collapsed selection to the beginning of the cell content', () => {
  1920. setModelData( model, modelTable( [
  1921. [ '00', '01', '02' ],
  1922. [ '10', 'word[] word' + text, '12' ],
  1923. [ '20', '21', '22' ]
  1924. ] ) );
  1925. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1926. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1927. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1928. assertEqualMarkup( getModelData( model ), modelTable( [
  1929. [ '00', '01', '02' ],
  1930. [ '10', '[word] word' + text, '12' ],
  1931. [ '20', '21', '22' ]
  1932. ] ) );
  1933. } );
  1934. it( 'should not prevent default browser behavior for shrinking selection (up arrow)', () => {
  1935. setModelData( model, modelTable( [
  1936. [ '00', '01', '02' ],
  1937. [ '10', 'word [word]' + text, '12' ],
  1938. [ '20', '21', '22' ]
  1939. ] ) );
  1940. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1941. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  1942. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  1943. } );
  1944. it( 'should expand not collapsed selection to the beginning of the cell content from the selection anchor', () => {
  1945. setModelData( model, modelTable( [
  1946. [ '00', '01', '02' ],
  1947. [ '10', 'word [word]' + text, '12' ],
  1948. [ '20', '21', '22' ]
  1949. ] ), { lastRangeBackward: true } );
  1950. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1951. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1952. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1953. assertEqualMarkup( getModelData( model ), modelTable( [
  1954. [ '00', '01', '02' ],
  1955. [ '10', '[word word]' + text, '12' ],
  1956. [ '20', '21', '22' ]
  1957. ] ) );
  1958. } );
  1959. it( 'should expand collapsed selection to the end of the cell content', () => {
  1960. setModelData( model, modelTable( [
  1961. [ '00', '01', '02' ],
  1962. [ '10', text + 'word[] word', '12' ],
  1963. [ '20', '21', '22' ]
  1964. ] ) );
  1965. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1966. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1967. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1968. assertEqualMarkup( getModelData( model ), modelTable( [
  1969. [ '00', '01', '02' ],
  1970. [ '10', text + 'word[ word]', '12' ],
  1971. [ '20', '21', '22' ]
  1972. ] ) );
  1973. } );
  1974. it( 'should not prevent default browser behavior for shrinking selection (down arrow)', () => {
  1975. setModelData( model, modelTable( [
  1976. [ '00', '01', '02' ],
  1977. [ '10', text + '[word] word', '12' ],
  1978. [ '20', '21', '22' ]
  1979. ] ), { lastRangeBackward: true } );
  1980. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1981. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  1982. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  1983. } );
  1984. it( 'should expand not collapsed selection to the end of the cell content from the selection anchor', () => {
  1985. setModelData( model, modelTable( [
  1986. [ '00', '01', '02' ],
  1987. [ '10', text + '[word] word', '12' ],
  1988. [ '20', '21', '22' ]
  1989. ] ) );
  1990. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1991. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1992. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1993. assertEqualMarkup( getModelData( model ), modelTable( [
  1994. [ '00', '01', '02' ],
  1995. [ '10', text + '[word word]', '12' ],
  1996. [ '20', '21', '22' ]
  1997. ] ) );
  1998. } );
  1999. } );
  2000. } );
  2001. if ( !env.isGecko ) {
  2002. // These tests fails on Travis. They work correctly when started on local machine.
  2003. // Issue is probably related to text rendering and wrapping.
  2004. describe( 'with selection in the wrap area', () => {
  2005. const text = new Array( 10 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  2006. it( 'should move the caret to end if the caret is after the last space in the line next to the last one', () => {
  2007. // This is also first position in the last line.
  2008. setModelData( model, modelTable( [
  2009. [ '00', '01', '02' ],
  2010. [ '10', text + ' []word word word', '12' ],
  2011. [ '20', '21', '22' ]
  2012. ] ) );
  2013. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2014. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2015. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2016. assertEqualMarkup( getModelData( model ), modelTable( [
  2017. [ '00', '01', '02' ],
  2018. [ '10', text + ' word word word[]', '12' ],
  2019. [ '20', '21', '22' ]
  2020. ] ) );
  2021. } );
  2022. it( 'should move the caret to end if ther caret is at the last space in the line next to last one', () => {
  2023. setModelData( model, modelTable( [
  2024. [ '00', '01', '02' ],
  2025. [ '10', text + '[] word word word', '12' ],
  2026. [ '20', '21', '22' ]
  2027. ] ) );
  2028. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2029. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2030. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2031. assertEqualMarkup( getModelData( model ), modelTable( [
  2032. [ '00', '01', '02' ],
  2033. [ '10', text + ' word word word[]', '12' ],
  2034. [ '20', '21', '22' ]
  2035. ] ) );
  2036. } );
  2037. it( 'should not move the caret if it\'s just before the last space in the line next to last one', () => {
  2038. setModelData( model, modelTable( [
  2039. [ '00', '01', '02' ],
  2040. [ '10', text.substring( 0, text.length - 1 ) + '[]d word word word', '12' ],
  2041. [ '20', '21', '22' ]
  2042. ] ) );
  2043. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2044. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  2045. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  2046. } );
  2047. describe( 'when shift key is pressed', () => {
  2048. beforeEach( () => {
  2049. upArrowDomEvtDataStub.shiftKey = true;
  2050. downArrowDomEvtDataStub.shiftKey = true;
  2051. } );
  2052. it( 'should expand collapsed selection to the end of the cell content', () => {
  2053. setModelData( model, modelTable( [
  2054. [ '00', '01', '02' ],
  2055. [ '10', text + '[] word word word', '12' ],
  2056. [ '20', '21', '22' ]
  2057. ] ) );
  2058. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2059. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2060. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2061. assertEqualMarkup( getModelData( model ), modelTable( [
  2062. [ '00', '01', '02' ],
  2063. [ '10', text + '[ word word word]', '12' ],
  2064. [ '20', '21', '22' ]
  2065. ] ) );
  2066. } );
  2067. it( 'should expand not collapsed selection to the end of the cell content from the selection anchor', () => {
  2068. setModelData( model, modelTable( [
  2069. [ '00', '01', '02' ],
  2070. [ '10', text + '[ word] word word', '12' ],
  2071. [ '20', '21', '22' ]
  2072. ] ) );
  2073. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2074. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2075. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2076. assertEqualMarkup( getModelData( model ), modelTable( [
  2077. [ '00', '01', '02' ],
  2078. [ '10', text + '[ word word word]', '12' ],
  2079. [ '20', '21', '22' ]
  2080. ] ) );
  2081. } );
  2082. } );
  2083. } );
  2084. }
  2085. describe( 'with multiple paragraphs of text', () => {
  2086. const text = new Array( 100 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  2087. it( 'should not navigate if caret is in the middle of a line of text', () => {
  2088. setModelData( model, modelTable( [
  2089. [ '00', '01', '02' ],
  2090. [ '10', `<paragraph>${ text }[]${ text }</paragraph><paragraph>foobar</paragraph>`, '12' ],
  2091. [ '20', '21', '22' ]
  2092. ] ) );
  2093. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2094. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  2095. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  2096. } );
  2097. it( 'should move the caret to the beginning of a cell content if the caret is in the first line of text', () => {
  2098. setModelData( model, modelTable( [
  2099. [ '00', '01', '02' ],
  2100. [ '10', `<paragraph>word[]${ text }</paragraph><paragraph>foobar</paragraph>`, '12' ],
  2101. [ '20', '21', '22' ]
  2102. ] ) );
  2103. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2104. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2105. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  2106. assertEqualMarkup( getModelData( model ), modelTable( [
  2107. [ '00', '01', '02' ],
  2108. [ '10', `<paragraph>[]word${ text }</paragraph><paragraph>foobar</paragraph>`, '12' ],
  2109. [ '20', '21', '22' ]
  2110. ] ) );
  2111. } );
  2112. it( 'should not move the caret to the end of a cell content if the caret is not in the last line of text', () => {
  2113. setModelData( model, modelTable( [
  2114. [ '00', '01', '02' ],
  2115. [ '10', `<paragraph>${ text }word []word</paragraph><paragraph>foobar</paragraph>`, '12' ],
  2116. [ '20', '21', '22' ]
  2117. ] ) );
  2118. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2119. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  2120. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  2121. } );
  2122. it( 'should move the caret to end of a cell content if the caret is in the last line of text', () => {
  2123. setModelData( model, modelTable( [
  2124. [ '00', '01', '02' ],
  2125. [ '10', `<paragraph>foobar</paragraph><paragraph>${ text }word []word</paragraph>`, '12' ],
  2126. [ '20', '21', '22' ]
  2127. ] ) );
  2128. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2129. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2130. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2131. assertEqualMarkup( getModelData( model ), modelTable( [
  2132. [ '00', '01', '02' ],
  2133. [ '10', `<paragraph>foobar</paragraph><paragraph>${ text }word word[]</paragraph>`, '12' ],
  2134. [ '20', '21', '22' ]
  2135. ] ) );
  2136. } );
  2137. describe( 'when shift key is pressed', () => {
  2138. beforeEach( () => {
  2139. upArrowDomEvtDataStub.shiftKey = true;
  2140. downArrowDomEvtDataStub.shiftKey = true;
  2141. } );
  2142. it( 'should expand selection to the beginning of the cell content', () => {
  2143. setModelData( model, modelTable( [
  2144. [ '00', '01', '02' ],
  2145. [ '10', `<paragraph>word[] ${ text }</paragraph><paragraph>${ text }</paragraph>`, '12' ],
  2146. [ '20', '21', '22' ]
  2147. ] ) );
  2148. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2149. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2150. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  2151. assertEqualMarkup( getModelData( model ), modelTable( [
  2152. [ '00', '01', '02' ],
  2153. [ '10', `<paragraph>[word] ${ text }</paragraph><paragraph>${ text }</paragraph>`, '12' ],
  2154. [ '20', '21', '22' ]
  2155. ] ) );
  2156. } );
  2157. it( 'should expand selection to the end of the cell content', () => {
  2158. setModelData( model, modelTable( [
  2159. [ '00', '01', '02' ],
  2160. [ '10', `<paragraph>${ text }</paragraph><paragraph>${ text } []word</paragraph>`, '12' ],
  2161. [ '20', '21', '22' ]
  2162. ] ) );
  2163. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2164. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2165. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2166. assertEqualMarkup( getModelData( model ), modelTable( [
  2167. [ '00', '01', '02' ],
  2168. [ '10', `<paragraph>${ text }</paragraph><paragraph>${ text } [word]</paragraph>`, '12' ],
  2169. [ '20', '21', '22' ]
  2170. ] ) );
  2171. } );
  2172. } );
  2173. } );
  2174. describe( 'with horizontal line widget', () => {
  2175. const text = new Array( 100 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  2176. it( 'should not navigate if the caret is in the middle line of text', () => {
  2177. setModelData( model, modelTable( [
  2178. [ '00', '01', '02' ],
  2179. [ '10', `<horizontalLine></horizontalLine><paragraph>${ text }[]${ text }</paragraph>`, '12' ],
  2180. [ '20', '21', '22' ]
  2181. ] ) );
  2182. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2183. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  2184. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  2185. } );
  2186. it( 'should move the caret to the beginning of cell content if the caret is in the first line of text', () => {
  2187. setModelData( model, modelTable( [
  2188. [ '00', '01', '02' ],
  2189. [ '10', `<horizontalLine></horizontalLine><paragraph>word[] ${ text }</paragraph>`, '12' ],
  2190. [ '20', '21', '22' ]
  2191. ] ) );
  2192. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2193. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2194. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  2195. assertEqualMarkup( getModelData( model ), modelTable( [
  2196. [ '00', '01', '02' ],
  2197. [ '10', `<horizontalLine></horizontalLine><paragraph>[]word ${ text }</paragraph>`, '12' ],
  2198. [ '20', '21', '22' ]
  2199. ] ) );
  2200. } );
  2201. it( 'should move the caret to the end of cell content if the caret is in the last line of text', () => {
  2202. setModelData( model, modelTable( [
  2203. [ '00', '01', '02' ],
  2204. [ '10', `<paragraph>${ text } word []word</paragraph><horizontalLine></horizontalLine>`, '12' ],
  2205. [ '20', '21', '22' ]
  2206. ] ) );
  2207. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2208. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2209. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2210. assertEqualMarkup( getModelData( model ), modelTable( [
  2211. [ '00', '01', '02' ],
  2212. [ '10', `<paragraph>${ text } word word[]</paragraph><horizontalLine></horizontalLine>`, '12' ],
  2213. [ '20', '21', '22' ]
  2214. ] ) );
  2215. } );
  2216. it( 'should not move the caret to the end of cell content if widget is selected in middle of a cell content', () => {
  2217. const paragraph = `<paragraph>${ text }</paragraph>`;
  2218. const hr = '<horizontalLine></horizontalLine>';
  2219. setModelData( model, modelTable( [
  2220. [ '00', '01', '02' ],
  2221. [ '10', `${ paragraph }[${ hr }]${ paragraph }${ hr }`, '12' ],
  2222. [ '20', '21', '22' ]
  2223. ] ) );
  2224. // Note: Two keydowns are necessary because the first one is handled by the WidgetTypeAround plugin
  2225. // to activate the "fake caret".
  2226. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2227. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2228. assertEqualMarkup( getModelData( model ), modelTable( [
  2229. [ '00', '01', '02' ],
  2230. [ '10', `${ paragraph }${ hr }<paragraph>[]${ text }</paragraph>${ hr }`, '12' ],
  2231. [ '20', '21', '22' ]
  2232. ] ) );
  2233. } );
  2234. it( 'should not move the caret to the end of cell content if widget is next to the selection', () => {
  2235. const paragraph = `<paragraph>${ text }</paragraph>`;
  2236. const hr = '<horizontalLine></horizontalLine>';
  2237. setModelData( model, modelTable( [
  2238. [ '00', '01', '02' ],
  2239. [ '10', `${ paragraph }[]${ hr }`, '12' ],
  2240. [ '20', '21', '22' ]
  2241. ] ) );
  2242. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2243. assertEqualMarkup( getModelData( model ), modelTable( [
  2244. [ '00', '01', '02' ],
  2245. [ '10', `${ paragraph }[${ hr }]`, '12' ],
  2246. [ '20', '21', '22' ]
  2247. ] ) );
  2248. } );
  2249. describe( 'when shift key is pressed', () => {
  2250. beforeEach( () => {
  2251. upArrowDomEvtDataStub.shiftKey = true;
  2252. downArrowDomEvtDataStub.shiftKey = true;
  2253. } );
  2254. it( 'should expand selection to the beginning of the cell content', () => {
  2255. setModelData( model, modelTable( [
  2256. [ '00', '01', '02' ],
  2257. [ '10', '<horizontalLine></horizontalLine><paragraph>foo[]bar</paragraph>', '12' ],
  2258. [ '20', '21', '22' ]
  2259. ] ) );
  2260. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2261. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2262. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  2263. assertEqualMarkup( getModelData( model ), modelTable( [
  2264. [ '00', '01', '02' ],
  2265. [ '10', '<horizontalLine></horizontalLine><paragraph>[foo]bar</paragraph>', '12' ],
  2266. [ '20', '21', '22' ]
  2267. ] ) );
  2268. } );
  2269. it( 'should expand selection to the end of the cell content', () => {
  2270. setModelData( model, modelTable( [
  2271. [ '00', '01', '02' ],
  2272. [ '10', '<paragraph>foo[]bar</paragraph><horizontalLine></horizontalLine>', '12' ],
  2273. [ '20', '21', '22' ]
  2274. ] ) );
  2275. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2276. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2277. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2278. assertEqualMarkup( getModelData( model ), modelTable( [
  2279. [ '00', '01', '02' ],
  2280. [ '10', '<paragraph>foo[bar]</paragraph><horizontalLine></horizontalLine>', '12' ],
  2281. [ '20', '21', '22' ]
  2282. ] ) );
  2283. } );
  2284. } );
  2285. } );
  2286. describe( 'contains image widget with caption and selection inside the caption', () => {
  2287. it( 'should not navigate to the cell on the left', () => {
  2288. setModelData( model, modelTable( [
  2289. [ '00', '01', '02' ],
  2290. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  2291. [ '20', '21', '22' ]
  2292. ] ) );
  2293. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  2294. sinon.assert.notCalled( leftArrowDomEvtDataStub.preventDefault );
  2295. sinon.assert.notCalled( leftArrowDomEvtDataStub.stopPropagation );
  2296. } );
  2297. it( 'should not navigate to the cell on the right', () => {
  2298. setModelData( model, modelTable( [
  2299. [ '00', '01', '02' ],
  2300. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image><paragraph>foo</paragraph>`, '12' ],
  2301. [ '20', '21', '22' ]
  2302. ] ) );
  2303. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  2304. sinon.assert.notCalled( rightArrowDomEvtDataStub.preventDefault );
  2305. sinon.assert.notCalled( rightArrowDomEvtDataStub.stopPropagation );
  2306. } );
  2307. it( 'should not navigate to the cell above (only to closest limit boundary)', () => {
  2308. setModelData( model, modelTable( [
  2309. [ '00', '01', '02' ],
  2310. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>1[]1</caption></image>`, '12' ],
  2311. [ '20', '21', '22' ]
  2312. ] ) );
  2313. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2314. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2315. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  2316. assertEqualMarkup( getModelData( model ), modelTable( [
  2317. [ '00', '01', '02' ],
  2318. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  2319. [ '20', '21', '22' ]
  2320. ] ) );
  2321. } );
  2322. it( 'should not navigate to the cell above (only to paragraph above)', () => {
  2323. setModelData( model, modelTable( [
  2324. [ '00', '01', '02' ],
  2325. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  2326. [ '20', '21', '22' ]
  2327. ] ) );
  2328. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2329. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  2330. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  2331. } );
  2332. it( 'should not navigate to the cell above but should put caret at first position of the image caption', () => {
  2333. setModelData( model, modelTable( [
  2334. [ '00', '01', '02' ],
  2335. [ '10', `<image src="${ imageUrl }"><caption>1[]1</caption></image><paragraph>foo</paragraph>`, '12' ],
  2336. [ '20', '21', '22' ]
  2337. ] ) );
  2338. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2339. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2340. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  2341. assertEqualMarkup( getModelData( model ), modelTable( [
  2342. [ '00', '01', '02' ],
  2343. [ '10', `<image src="${ imageUrl }"><caption>[]11</caption></image><paragraph>foo</paragraph>`, '12' ],
  2344. [ '20', '21', '22' ]
  2345. ] ) );
  2346. } );
  2347. it( 'should not navigate to the cell below when inside the image caption', () => {
  2348. setModelData( model, modelTable( [
  2349. [ '00', '01', '02' ],
  2350. [ '10', `<image src="${ imageUrl }"><caption>1[]1</caption></image><paragraph>foo</paragraph>`, '12' ],
  2351. [ '20', '21', '22' ]
  2352. ] ) );
  2353. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2354. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2355. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2356. assertEqualMarkup( getModelData( model ), modelTable( [
  2357. [ '00', '01', '02' ],
  2358. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image><paragraph>foo</paragraph>`, '12' ],
  2359. [ '20', '21', '22' ]
  2360. ] ) );
  2361. } );
  2362. it( 'should not navigate to the cell below when followed by a paragraph', () => {
  2363. setModelData( model, modelTable( [
  2364. [ '00', '01', '02' ],
  2365. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image><paragraph>foo</paragraph>`, '12' ],
  2366. [ '20', '21', '22' ]
  2367. ] ) );
  2368. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2369. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  2370. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  2371. } );
  2372. it( 'should navigate to the cell below if the caret on last position in the image caption', () => {
  2373. setModelData( model, modelTable( [
  2374. [ '00', '01', '02' ],
  2375. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>11[]</caption></image>`, '12' ],
  2376. [ '20', '21', '22' ]
  2377. ] ) );
  2378. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2379. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2380. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2381. assertEqualMarkup( getModelData( model ), modelTable( [
  2382. [ '00', '01', '02' ],
  2383. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>11</caption></image>`, '12' ],
  2384. [ '20', '[]21', '22' ]
  2385. ] ) );
  2386. } );
  2387. it( 'should not navigate to the cell above but should select the image widget without caption', () => {
  2388. setModelData( model, modelTable( [
  2389. [ '00', '01', '02' ],
  2390. [ '10', `<image src="${ imageUrl }"><caption></caption></image><paragraph>[]foo</paragraph>`, '12' ],
  2391. [ '20', '21', '22' ]
  2392. ] ) );
  2393. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2394. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2395. assertEqualMarkup( getModelData( model ), modelTable( [
  2396. [ '00', '01', '02' ],
  2397. [ '10', `[<image src="${ imageUrl }"><caption></caption></image>]<paragraph>foo</paragraph>`, '12' ],
  2398. [ '20', '21', '22' ]
  2399. ] ) );
  2400. } );
  2401. it( 'should not navigate to the cell below but should select the image widget without caption', () => {
  2402. setModelData( model, modelTable( [
  2403. [ '00', '01', '02' ],
  2404. [ '10', `<paragraph>foo[]</paragraph><image src="${ imageUrl }"><caption></caption></image>`, '12' ],
  2405. [ '20', '21', '22' ]
  2406. ] ) );
  2407. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2408. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2409. assertEqualMarkup( getModelData( model ), modelTable( [
  2410. [ '00', '01', '02' ],
  2411. [ '10', `<paragraph>foo</paragraph>[<image src="${ imageUrl }"><caption></caption></image>]`, '12' ],
  2412. [ '20', '21', '22' ]
  2413. ] ) );
  2414. } );
  2415. } );
  2416. } );
  2417. } );
  2418. describe( 'for right-to-left content language', () => {
  2419. let editor, model, modelRoot, tableSelection;
  2420. beforeEach( () => {
  2421. return VirtualTestEditor
  2422. .create( {
  2423. plugins: [ TableEditing, TableKeyboard, TableSelection, Paragraph, ImageEditing, MediaEmbedEditing ],
  2424. language: 'ar'
  2425. } )
  2426. .then( newEditor => {
  2427. editor = newEditor;
  2428. model = editor.model;
  2429. modelRoot = model.document.getRoot();
  2430. tableSelection = editor.plugins.get( TableSelection );
  2431. } );
  2432. } );
  2433. afterEach( () => {
  2434. return editor.destroy();
  2435. } );
  2436. describe( 'with the table cell selected from outside', () => {
  2437. beforeEach( () => {
  2438. setModelData( model, modelTable( [
  2439. [ '00', '01', '02' ],
  2440. [ '10', '11', '12' ],
  2441. [ '20', '21', '22' ]
  2442. ] ) );
  2443. tableSelection.setCellSelection(
  2444. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  2445. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  2446. );
  2447. } );
  2448. it( 'should move to the cell on the right (visually flipped by the browser)', () => {
  2449. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  2450. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  2451. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  2452. assertEqualMarkup( getModelData( model ), modelTable( [
  2453. [ '00', '01', '02' ],
  2454. [ '10', '11', '[]12' ],
  2455. [ '20', '21', '22' ]
  2456. ] ) );
  2457. } );
  2458. it( 'should move to the cell on the left (visually flipped by the browser)', () => {
  2459. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  2460. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  2461. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  2462. assertEqualMarkup( getModelData( model ), modelTable( [
  2463. [ '00', '01', '02' ],
  2464. [ '10[]', '11', '12' ],
  2465. [ '20', '21', '22' ]
  2466. ] ) );
  2467. } );
  2468. it( 'should move to the cell above the selection', () => {
  2469. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  2470. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  2471. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  2472. assertEqualMarkup( getModelData( model ), modelTable( [
  2473. [ '00', '01[]', '02' ],
  2474. [ '10', '11', '12' ],
  2475. [ '20', '21', '22' ]
  2476. ] ) );
  2477. } );
  2478. it( 'should move to the cell below the selection', () => {
  2479. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  2480. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  2481. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  2482. assertEqualMarkup( getModelData( model ), modelTable( [
  2483. [ '00', '01', '02' ],
  2484. [ '10', '11', '12' ],
  2485. [ '20', '[]21', '22' ]
  2486. ] ) );
  2487. } );
  2488. } );
  2489. } );
  2490. } );
  2491. } );