tablenavigation.js 81 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277
  1. import { getCode } from '@ckeditor/ckeditor5-utils/src/keyboard';
  2. import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
  3. import { modelTable } from './_utils/utils';
  4. import { assertEqualMarkup } from '@ckeditor/ckeditor5-utils/tests/_utils/utils';
  5. import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
  6. import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
  7. import ImageEditing from '@ckeditor/ckeditor5-image/src/image/imageediting';
  8. import MediaEmbedEditing from '@ckeditor/ckeditor5-media-embed/src/mediaembedediting';
  9. import TableNavigation from '../src/tablenavigation';
  10. import Table from '../src/table';
  11. import TableEditing from '../src/tableediting';
  12. import TableSelection from '../src/tableselection';
  13. import ImageCaptionEditing from '@ckeditor/ckeditor5-image/src/imagecaption/imagecaptionediting';
  14. import HorizontalLineEditing from '@ckeditor/ckeditor5-horizontal-line/src/horizontallineediting';
  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 global from '@ckeditor/ckeditor5-utils/src/dom/global';
  20. import env from '@ckeditor/ckeditor5-utils/src/env';
  21. describe( 'TableNavigation', () => {
  22. let editor, model, modelRoot, tableSelection;
  23. const imageUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAUCAQAAADRyVAeAAAAKklEQVR42u3PAQ0AAAwCI' +
  24. 'O0f+u/hoAHNZUJFRERERERERERERERERLYiD9N4FAFj2iK6AAAAAElFTkSuQmCC';
  25. beforeEach( () => {
  26. return VirtualTestEditor
  27. .create( {
  28. plugins: [ TableEditing, TableNavigation, TableSelection, Paragraph, ImageEditing, ImageCaptionEditing, MediaEmbedEditing,
  29. HorizontalLineEditing ]
  30. } )
  31. .then( newEditor => {
  32. editor = newEditor;
  33. model = editor.model;
  34. modelRoot = model.document.getRoot();
  35. tableSelection = editor.plugins.get( TableSelection );
  36. } );
  37. } );
  38. afterEach( () => {
  39. editor.destroy();
  40. } );
  41. it( 'should have pluginName', () => {
  42. expect( TableNavigation.pluginName ).to.equal( 'TableNavigation' );
  43. } );
  44. describe( 'Tab key handling', () => {
  45. let domEvtDataStub;
  46. beforeEach( () => {
  47. domEvtDataStub = {
  48. keyCode: getCode( 'Tab' ),
  49. preventDefault: sinon.spy(),
  50. stopPropagation: sinon.spy()
  51. };
  52. } );
  53. it( 'should do nothing if not tab pressed', () => {
  54. setModelData( model, modelTable( [
  55. [ '11', '12[]' ]
  56. ] ) );
  57. domEvtDataStub.keyCode = getCode( 'a' );
  58. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  59. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  60. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  61. assertEqualMarkup( getModelData( model ), modelTable( [
  62. [ '11', '12[]' ]
  63. ] ) );
  64. } );
  65. it( 'should do nothing if Ctrl+Tab is pressed', () => {
  66. setModelData( model, modelTable( [
  67. [ '11', '12[]' ]
  68. ] ) );
  69. domEvtDataStub.ctrlKey = true;
  70. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  71. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  72. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  73. assertEqualMarkup( getModelData( model ), modelTable( [
  74. [ '11', '12[]' ]
  75. ] ) );
  76. } );
  77. describe( 'on TAB', () => {
  78. it( 'should do nothing if selection is not in a table', () => {
  79. setModelData( model, '<paragraph>[]</paragraph>' + modelTable( [ [ '11', '12' ] ] ) );
  80. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  81. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  82. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  83. assertEqualMarkup( getModelData( model ), '<paragraph>[]</paragraph>' + modelTable( [
  84. [ '11', '12' ]
  85. ] ) );
  86. } );
  87. it( 'should move to next cell', () => {
  88. setModelData( model, modelTable( [
  89. [ '11[]', '12' ]
  90. ] ) );
  91. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  92. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  93. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  94. assertEqualMarkup( getModelData( model ), modelTable( [
  95. [ '11', '[12]' ]
  96. ] ) );
  97. } );
  98. it( 'should create another row and move to first cell in new row', () => {
  99. setModelData( model, modelTable( [
  100. [ '11', '[12]' ]
  101. ] ) );
  102. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  103. assertEqualMarkup( getModelData( model ), modelTable( [
  104. [ '11', '12' ],
  105. [ '[]', '' ]
  106. ] ) );
  107. } );
  108. it( 'should not create another row and not move the caret if insertTableRowBelow command is disabled', () => {
  109. setModelData( model, modelTable( [
  110. [ '11', '12[]' ]
  111. ] ) );
  112. const insertTableRowBelowCommand = editor.commands.get( 'insertTableRowBelow' );
  113. insertTableRowBelowCommand.forceDisabled( 'test' );
  114. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  115. assertEqualMarkup( getModelData( model ), modelTable( [
  116. [ '11', '12[]' ]
  117. ] ) );
  118. } );
  119. it( 'should move to the first cell of next row if on end of a row', () => {
  120. setModelData( model, modelTable( [
  121. [ '11', '12[]' ],
  122. [ '21', '22' ]
  123. ] ) );
  124. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  125. assertEqualMarkup( getModelData( model ), modelTable( [
  126. [ '11', '12' ],
  127. [ '[21]', '22' ]
  128. ] ) );
  129. } );
  130. it( 'should move to the next table cell if part of block content is selected', () => {
  131. setModelData( model, modelTable( [
  132. [ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ]
  133. ] ) );
  134. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  135. assertEqualMarkup( getModelData( model ), modelTable( [
  136. [
  137. '11',
  138. '<paragraph>12</paragraph><paragraph>foo</paragraph><paragraph>bar</paragraph>',
  139. '[13]'
  140. ]
  141. ] ) );
  142. } );
  143. it( 'should move to next cell with an image', () => {
  144. setModelData( model, modelTable( [
  145. [ '11[]', '<paragraph>foo</paragraph><image><caption></caption></image>' ]
  146. ] ) );
  147. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  148. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  149. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  150. assertEqualMarkup( getModelData( model ), modelTable( [
  151. [ '11', '<paragraph>[foo</paragraph><image><caption></caption></image>]' ]
  152. ] ) );
  153. } );
  154. it( 'should move to next cell with an blockQuote', () => {
  155. model.schema.register( 'blockQuote', {
  156. allowWhere: '$block',
  157. allowContentOf: '$root'
  158. } );
  159. editor.conversion.elementToElement( { model: 'blockQuote', view: 'blockquote' } );
  160. setModelData( model, modelTable( [
  161. [ '11[]', '<blockQuote><paragraph>foo</paragraph></blockQuote>' ]
  162. ] ) );
  163. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  164. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  165. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  166. assertEqualMarkup( getModelData( model ), modelTable( [
  167. [ '11', '<blockQuote><paragraph>[foo]</paragraph></blockQuote>' ]
  168. ] ) );
  169. } );
  170. it( 'should listen with lower priority then its children', () => {
  171. // Cancel TAB event.
  172. editor.keystrokes.set( 'Tab', ( data, cancel ) => cancel() );
  173. setModelData( model, modelTable( [
  174. [ '11[]', '12' ]
  175. ] ) );
  176. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  177. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  178. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  179. assertEqualMarkup( getModelData( model ), modelTable( [
  180. [ '11[]', '12' ]
  181. ] ) );
  182. } );
  183. describe( 'on table widget selected', () => {
  184. beforeEach( () => {
  185. editor.model.schema.register( 'block', {
  186. allowWhere: '$block',
  187. allowContentOf: '$block',
  188. isObject: true
  189. } );
  190. editor.conversion.elementToElement( { model: 'block', view: 'block' } );
  191. } );
  192. it( 'should move caret to the first table cell on TAB', () => {
  193. const spy = sinon.spy();
  194. editor.keystrokes.set( 'Tab', spy, { priority: 'lowest' } );
  195. setModelData( model, '[' + modelTable( [
  196. [ '11', '12' ]
  197. ] ) + ']' );
  198. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  199. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  200. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  201. assertEqualMarkup( getModelData( model ), modelTable( [
  202. [ '[11]', '12' ]
  203. ] ) );
  204. // Should cancel event - so no other tab handler is called.
  205. sinon.assert.notCalled( spy );
  206. } );
  207. it( 'shouldn\'t do anything on other blocks', () => {
  208. const spy = sinon.spy();
  209. editor.editing.view.document.on( 'keydown', spy );
  210. setModelData( model, '[<block>foo</block>]' );
  211. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  212. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  213. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  214. assertEqualMarkup( getModelData( model ), '[<block>foo</block>]' );
  215. // Should not cancel event.
  216. sinon.assert.calledOnce( spy );
  217. } );
  218. } );
  219. } );
  220. describe( 'on SHIFT+TAB', () => {
  221. beforeEach( () => {
  222. domEvtDataStub.shiftKey = true;
  223. } );
  224. it( 'should do nothing if selection is not in a table', () => {
  225. setModelData( model, '<paragraph>[]</paragraph>' + modelTable( [
  226. [ '11', '12' ]
  227. ] ) );
  228. domEvtDataStub.keyCode = getCode( 'Tab' );
  229. domEvtDataStub.shiftKey = true;
  230. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  231. sinon.assert.notCalled( domEvtDataStub.preventDefault );
  232. sinon.assert.notCalled( domEvtDataStub.stopPropagation );
  233. assertEqualMarkup( getModelData( model ), '<paragraph>[]</paragraph>' + modelTable( [
  234. [ '11', '12' ]
  235. ] ) );
  236. } );
  237. it( 'should move to previous cell', () => {
  238. setModelData( model, modelTable( [
  239. [ '11', '12[]' ]
  240. ] ) );
  241. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  242. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  243. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  244. assertEqualMarkup( getModelData( model ), modelTable( [
  245. [ '[11]', '12' ]
  246. ] ) );
  247. } );
  248. it( 'should not move if caret is in first table cell', () => {
  249. setModelData( model, '<paragraph>foo</paragraph>' + modelTable( [
  250. [ '[]11', '12' ]
  251. ] ) );
  252. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  253. assertEqualMarkup( getModelData( model ),
  254. '<paragraph>foo</paragraph>' + modelTable( [ [ '[]11', '12' ] ] )
  255. );
  256. } );
  257. it( 'should move to the last cell of previous row if on beginning of a row', () => {
  258. setModelData( model, modelTable( [
  259. [ '11', '12' ],
  260. [ '[]21', '22' ]
  261. ] ) );
  262. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  263. assertEqualMarkup( getModelData( model ), modelTable( [
  264. [ '11', '[12]' ],
  265. [ '21', '22' ]
  266. ] ) );
  267. } );
  268. it( 'should move to the previous table cell if part of block content is selected', () => {
  269. setModelData( model, modelTable( [
  270. [ '11', '<paragraph>12</paragraph><paragraph>[foo]</paragraph><paragraph>bar</paragraph>', '13' ]
  271. ] ) );
  272. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  273. assertEqualMarkup( getModelData( model ), modelTable( [
  274. [
  275. '[11]',
  276. '<paragraph>12</paragraph><paragraph>foo</paragraph><paragraph>bar</paragraph>',
  277. '13'
  278. ]
  279. ] ) );
  280. } );
  281. it( 'should move to previous cell with an image', () => {
  282. setModelData( model, modelTable( [
  283. [ '<paragraph>foo</paragraph><image><caption></caption></image>', 'bar[]' ]
  284. ] ) );
  285. editor.editing.view.document.fire( 'keydown', domEvtDataStub );
  286. sinon.assert.calledOnce( domEvtDataStub.preventDefault );
  287. sinon.assert.calledOnce( domEvtDataStub.stopPropagation );
  288. assertEqualMarkup( getModelData( model ), modelTable( [
  289. [ '<paragraph>[foo</paragraph><image><caption></caption></image>]', 'bar' ]
  290. ] ) );
  291. } );
  292. } );
  293. } );
  294. describe( 'Arrow keys handling', () => {
  295. let leftArrowDomEvtDataStub, rightArrowDomEvtDataStub, upArrowDomEvtDataStub, downArrowDomEvtDataStub;
  296. beforeEach( () => {
  297. leftArrowDomEvtDataStub = {
  298. keyCode: getCode( 'ArrowLeft' ),
  299. preventDefault: sinon.spy(),
  300. stopPropagation: sinon.spy(),
  301. domTarget: global.document.body
  302. };
  303. rightArrowDomEvtDataStub = {
  304. keyCode: getCode( 'ArrowRight' ),
  305. preventDefault: sinon.spy(),
  306. stopPropagation: sinon.spy(),
  307. domTarget: global.document.body
  308. };
  309. upArrowDomEvtDataStub = {
  310. keyCode: getCode( 'ArrowUp' ),
  311. preventDefault: sinon.spy(),
  312. stopPropagation: sinon.spy(),
  313. domTarget: global.document.body
  314. };
  315. downArrowDomEvtDataStub = {
  316. keyCode: getCode( 'ArrowDown' ),
  317. preventDefault: sinon.spy(),
  318. stopPropagation: sinon.spy(),
  319. domTarget: global.document.body
  320. };
  321. } );
  322. it( 'should do nothing if not arrow key pressed', () => {
  323. setModelData( model, modelTable( [
  324. [ '00', '01[]' ]
  325. ] ) );
  326. leftArrowDomEvtDataStub.keyCode = getCode( 'a' );
  327. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  328. sinon.assert.notCalled( leftArrowDomEvtDataStub.preventDefault );
  329. sinon.assert.notCalled( leftArrowDomEvtDataStub.stopPropagation );
  330. assertEqualMarkup( getModelData( model ), modelTable( [
  331. [ '00', '01[]' ]
  332. ] ) );
  333. } );
  334. it( 'should do nothing if selection is not in a table', () => {
  335. const modelData = '<paragraph>[]foobar</paragraph>' + modelTable( [ [ '00', '01' ] ] );
  336. setModelData( model, modelData );
  337. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  338. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  339. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  340. assertEqualMarkup( getModelData( model ), modelData );
  341. } );
  342. describe( '#_navigateFromCellInDirection (finding proper cell to move selection to)', () => {
  343. let tableNavigation;
  344. beforeEach( () => {
  345. tableNavigation = editor.plugins.get( TableNavigation );
  346. } );
  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 direction is "right"', () => {
  361. tableNavigation._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 the cell below when direction is "down"', () => {
  369. tableNavigation._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 direction is "up"', () => {
  377. tableNavigation._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 direction is "left"', () => {
  385. tableNavigation._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 direction is "left"', () => {
  399. tableNavigation._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 direction is "up"', () => {
  407. tableNavigation._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 direction is "down"', () => {
  415. tableNavigation._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 direction is "right"', () => {
  423. tableNavigation._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 direction is "right"', () => {
  437. tableNavigation._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 direction is "up"', () => {
  445. tableNavigation._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 direction is "down"', () => {
  453. tableNavigation._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 direction is "left"', () => {
  461. tableNavigation._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 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 direction is "left"', () => {
  475. tableNavigation._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 direction is "up"', () => {
  483. tableNavigation._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 direction is "down"', () => {
  491. tableNavigation._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 direction is "right"', () => {
  499. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. tableNavigation._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. } );
  803. describe( 'with the table cells selected from outside', () => {
  804. describe( 'on single table cell selected', () => {
  805. beforeEach( () => {
  806. setModelData( model, modelTable( [
  807. [ '00', '01', '02' ],
  808. [ '10', '11', '12' ],
  809. [ '20', '21', '22' ]
  810. ] ) );
  811. tableSelection._setCellSelection(
  812. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  813. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  814. );
  815. } );
  816. it( 'should move to the cell on the left', () => {
  817. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  818. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  819. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  820. assertEqualMarkup( getModelData( model ), modelTable( [
  821. [ '00', '01', '02' ],
  822. [ '10[]', '11', '12' ],
  823. [ '20', '21', '22' ]
  824. ] ) );
  825. } );
  826. it( 'should move to the cell on the right', () => {
  827. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  828. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  829. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  830. assertEqualMarkup( getModelData( model ), modelTable( [
  831. [ '00', '01', '02' ],
  832. [ '10', '11', '[]12' ],
  833. [ '20', '21', '22' ]
  834. ] ) );
  835. } );
  836. it( 'should move to the cell above selection', () => {
  837. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  838. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  839. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  840. assertEqualMarkup( getModelData( model ), modelTable( [
  841. [ '00', '01[]', '02' ],
  842. [ '10', '11', '12' ],
  843. [ '20', '21', '22' ]
  844. ] ) );
  845. } );
  846. it( 'should move to the cell below selection', () => {
  847. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  848. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  849. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  850. assertEqualMarkup( getModelData( model ), modelTable( [
  851. [ '00', '01', '02' ],
  852. [ '10', '11', '12' ],
  853. [ '20', '[]21', '22' ]
  854. ] ) );
  855. } );
  856. } );
  857. describe( 'on multiple table cell selected vertically', () => {
  858. beforeEach( () => {
  859. setModelData( model, modelTable( [
  860. [ '00', '01', '02', '03' ],
  861. [ '10', '11', '12', '13' ],
  862. [ '20', '21', '22', '23' ],
  863. [ '30', '31', '32', '33' ]
  864. ] ) );
  865. tableSelection._setCellSelection(
  866. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  867. modelRoot.getNodeByPath( [ 0, 2, 1 ] )
  868. );
  869. } );
  870. it( 'should move to the cell on the left top of selection', () => {
  871. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  872. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  873. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  874. assertEqualMarkup( getModelData( model ), modelTable( [
  875. [ '00', '01', '02', '03' ],
  876. [ '10[]', '11', '12', '13' ],
  877. [ '20', '21', '22', '23' ],
  878. [ '30', '31', '32', '33' ]
  879. ] ) );
  880. } );
  881. it( 'should move to the cell on the right bottom of selection', () => {
  882. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  883. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  884. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  885. assertEqualMarkup( getModelData( model ), modelTable( [
  886. [ '00', '01', '02', '03' ],
  887. [ '10', '11', '12', '13' ],
  888. [ '20', '21', '[]22', '23' ],
  889. [ '30', '31', '32', '33' ]
  890. ] ) );
  891. } );
  892. it( 'should move to the cell above selection', () => {
  893. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  894. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  895. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  896. assertEqualMarkup( getModelData( model ), modelTable( [
  897. [ '00', '01[]', '02', '03' ],
  898. [ '10', '11', '12', '13' ],
  899. [ '20', '21', '22', '23' ],
  900. [ '30', '31', '32', '33' ]
  901. ] ) );
  902. } );
  903. it( 'should move to the cell below selection', () => {
  904. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  905. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  906. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  907. assertEqualMarkup( getModelData( model ), modelTable( [
  908. [ '00', '01', '02', '03' ],
  909. [ '10', '11', '12', '13' ],
  910. [ '20', '21', '22', '23' ],
  911. [ '30', '[]31', '32', '33' ]
  912. ] ) );
  913. } );
  914. } );
  915. describe( 'on multiple table cell selected horizontally', () => {
  916. beforeEach( () => {
  917. setModelData( model, modelTable( [
  918. [ '00', '01', '02', '03' ],
  919. [ '10', '11', '12', '13' ],
  920. [ '20', '21', '22', '23' ],
  921. [ '30', '31', '32', '33' ]
  922. ] ) );
  923. // Note that this also tests that selection direction doesn't matter.
  924. tableSelection._setCellSelection(
  925. modelRoot.getNodeByPath( [ 0, 1, 2 ] ),
  926. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  927. );
  928. } );
  929. it( 'should move to the cell on the left top of selection', () => {
  930. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  931. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  932. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  933. assertEqualMarkup( getModelData( model ), modelTable( [
  934. [ '00', '01', '02', '03' ],
  935. [ '10[]', '11', '12', '13' ],
  936. [ '20', '21', '22', '23' ],
  937. [ '30', '31', '32', '33' ]
  938. ] ) );
  939. } );
  940. it( 'should move to the cell on the right bottom of selection', () => {
  941. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  942. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  943. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  944. assertEqualMarkup( getModelData( model ), modelTable( [
  945. [ '00', '01', '02', '03' ],
  946. [ '10', '11', '12', '[]13' ],
  947. [ '20', '21', '22', '23' ],
  948. [ '30', '31', '32', '33' ]
  949. ] ) );
  950. } );
  951. it( 'should move to the cell above selection', () => {
  952. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  953. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  954. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  955. assertEqualMarkup( getModelData( model ), modelTable( [
  956. [ '00', '01[]', '02', '03' ],
  957. [ '10', '11', '12', '13' ],
  958. [ '20', '21', '22', '23' ],
  959. [ '30', '31', '32', '33' ]
  960. ] ) );
  961. } );
  962. it( 'should move to the cell below selection', () => {
  963. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  964. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  965. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  966. assertEqualMarkup( getModelData( model ), modelTable( [
  967. [ '00', '01', '02', '03' ],
  968. [ '10', '11', '12', '13' ],
  969. [ '20', '21', '[]22', '23' ],
  970. [ '30', '31', '32', '33' ]
  971. ] ) );
  972. } );
  973. } );
  974. describe( 'on multiple table cell selected diagonally', () => {
  975. beforeEach( () => {
  976. setModelData( model, modelTable( [
  977. [ '00', '01', '02', '03' ],
  978. [ '10', '11', '12', '13' ],
  979. [ '20', '21', '22', '23' ],
  980. [ '30', '31', '32', '33' ]
  981. ] ) );
  982. tableSelection._setCellSelection(
  983. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  984. modelRoot.getNodeByPath( [ 0, 2, 2 ] )
  985. );
  986. } );
  987. it( 'should move to the cell on the left top of selection', () => {
  988. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  989. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  990. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  991. assertEqualMarkup( getModelData( model ), modelTable( [
  992. [ '00', '01', '02', '03' ],
  993. [ '10[]', '11', '12', '13' ],
  994. [ '20', '21', '22', '23' ],
  995. [ '30', '31', '32', '33' ]
  996. ] ) );
  997. } );
  998. it( 'should move to the cell on the right bottom of selection', () => {
  999. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1000. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1001. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1002. assertEqualMarkup( getModelData( model ), modelTable( [
  1003. [ '00', '01', '02', '03' ],
  1004. [ '10', '11', '12', '13' ],
  1005. [ '20', '21', '22', '[]23' ],
  1006. [ '30', '31', '32', '33' ]
  1007. ] ) );
  1008. } );
  1009. it( 'should move to the cell above selection', () => {
  1010. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1011. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1012. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1013. assertEqualMarkup( getModelData( model ), modelTable( [
  1014. [ '00', '01[]', '02', '03' ],
  1015. [ '10', '11', '12', '13' ],
  1016. [ '20', '21', '22', '23' ],
  1017. [ '30', '31', '32', '33' ]
  1018. ] ) );
  1019. } );
  1020. it( 'should move to the cell below selection', () => {
  1021. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1022. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1023. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1024. assertEqualMarkup( getModelData( model ), modelTable( [
  1025. [ '00', '01', '02', '03' ],
  1026. [ '10', '11', '12', '13' ],
  1027. [ '20', '21', '22', '23' ],
  1028. [ '30', '31', '[]32', '33' ]
  1029. ] ) );
  1030. } );
  1031. } );
  1032. } );
  1033. describe( 'with selection inside a table cell', () => {
  1034. describe( 'with selection at the edge of a cell', () => {
  1035. describe( 'simple cell text content', () => {
  1036. it( 'should navigate to the cell on the left', () => {
  1037. setModelData( model, modelTable( [
  1038. [ '00', '01', '02' ],
  1039. [ '10', '[]11', '12' ],
  1040. [ '20', '21', '22' ]
  1041. ] ) );
  1042. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1043. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1044. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1045. assertEqualMarkup( getModelData( model ), modelTable( [
  1046. [ '00', '01', '02' ],
  1047. [ '10[]', '11', '12' ],
  1048. [ '20', '21', '22' ]
  1049. ] ) );
  1050. } );
  1051. it( 'should navigate to the cell on the right', () => {
  1052. setModelData( model, modelTable( [
  1053. [ '00', '01', '02' ],
  1054. [ '10', '11[]', '12' ],
  1055. [ '20', '21', '22' ]
  1056. ] ) );
  1057. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1058. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1059. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1060. assertEqualMarkup( getModelData( model ), modelTable( [
  1061. [ '00', '01', '02' ],
  1062. [ '10', '11', '[]12' ],
  1063. [ '20', '21', '22' ]
  1064. ] ) );
  1065. } );
  1066. it( 'should navigate to the cell above', () => {
  1067. setModelData( model, modelTable( [
  1068. [ '00', '01', '02' ],
  1069. [ '10', '[]11', '12' ],
  1070. [ '20', '21', '22' ]
  1071. ] ) );
  1072. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1073. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1074. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1075. assertEqualMarkup( getModelData( model ), modelTable( [
  1076. [ '00', '01[]', '02' ],
  1077. [ '10', '11', '12' ],
  1078. [ '20', '21', '22' ]
  1079. ] ) );
  1080. } );
  1081. it( 'should navigate to the cell below', () => {
  1082. setModelData( model, modelTable( [
  1083. [ '00', '01', '02' ],
  1084. [ '10', '11[]', '12' ],
  1085. [ '20', '21', '22' ]
  1086. ] ) );
  1087. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1088. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1089. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1090. assertEqualMarkup( getModelData( model ), modelTable( [
  1091. [ '00', '01', '02' ],
  1092. [ '10', '11', '12' ],
  1093. [ '20', '[]21', '22' ]
  1094. ] ) );
  1095. } );
  1096. } );
  1097. describe( 'multiple paragraphs in the cell content', () => {
  1098. it( 'should navigate to the cell on the left', () => {
  1099. setModelData( model, modelTable( [
  1100. [ '00', '01', '02' ],
  1101. [ '10', '<paragraph>[]11</paragraph><paragraph>x</paragraph>', '12' ],
  1102. [ '20', '21', '22' ]
  1103. ] ) );
  1104. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1105. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1106. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1107. assertEqualMarkup( getModelData( model ), modelTable( [
  1108. [ '00', '01', '02' ],
  1109. [ '10[]', '<paragraph>11</paragraph><paragraph>x</paragraph>', '12' ],
  1110. [ '20', '21', '22' ]
  1111. ] ) );
  1112. } );
  1113. it( 'should navigate to the cell on the right', () => {
  1114. setModelData( model, modelTable( [
  1115. [ '00', '01', '02' ],
  1116. [ '10', '<paragraph>11</paragraph><paragraph>x[]</paragraph>', '12' ],
  1117. [ '20', '21', '22' ]
  1118. ] ) );
  1119. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1120. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1121. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1122. assertEqualMarkup( getModelData( model ), modelTable( [
  1123. [ '00', '01', '02' ],
  1124. [ '10', '<paragraph>11</paragraph><paragraph>x</paragraph>', '[]12' ],
  1125. [ '20', '21', '22' ]
  1126. ] ) );
  1127. } );
  1128. it( 'should navigate to the cell above', () => {
  1129. setModelData( model, modelTable( [
  1130. [ '00', '01', '02' ],
  1131. [ '10', '<paragraph>[]11</paragraph><paragraph>x</paragraph>', '12' ],
  1132. [ '20', '21', '22' ]
  1133. ] ) );
  1134. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1135. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1136. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1137. assertEqualMarkup( getModelData( model ), modelTable( [
  1138. [ '00', '01[]', '02' ],
  1139. [ '10', '<paragraph>11</paragraph><paragraph>x</paragraph>', '12' ],
  1140. [ '20', '21', '22' ]
  1141. ] ) );
  1142. } );
  1143. it( 'should navigate to the cell below', () => {
  1144. setModelData( model, modelTable( [
  1145. [ '00', '01', '02' ],
  1146. [ '10', '<paragraph>11</paragraph><paragraph>x[]</paragraph>', '12' ],
  1147. [ '20', '21', '22' ]
  1148. ] ) );
  1149. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1150. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1151. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1152. assertEqualMarkup( getModelData( model ), modelTable( [
  1153. [ '00', '01', '02' ],
  1154. [ '10', '<paragraph>11</paragraph><paragraph>x</paragraph>', '12' ],
  1155. [ '20', '[]21', '22' ]
  1156. ] ) );
  1157. } );
  1158. } );
  1159. describe( 'image widget with caption as only cell content', () => {
  1160. it( 'should navigate to the cell on the left', () => {
  1161. setModelData( model, modelTable( [
  1162. [ '00', '01', '02' ],
  1163. [ '10', `<image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  1164. [ '20', '21', '22' ]
  1165. ] ) );
  1166. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1167. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1168. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1169. assertEqualMarkup( getModelData( model ), modelTable( [
  1170. [ '00', '01', '02' ],
  1171. [ '10[]', `<image src="${ imageUrl }"><caption>11</caption></image>`, '12' ],
  1172. [ '20', '21', '22' ]
  1173. ] ) );
  1174. } );
  1175. it( 'should navigate to the cell on the right', () => {
  1176. setModelData( model, modelTable( [
  1177. [ '00', '01', '02' ],
  1178. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image>`, '12' ],
  1179. [ '20', '21', '22' ]
  1180. ] ) );
  1181. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1182. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1183. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1184. assertEqualMarkup( getModelData( model ), modelTable( [
  1185. [ '00', '01', '02' ],
  1186. [ '10', `<image src="${ imageUrl }"><caption>11</caption></image>`, '[]12' ],
  1187. [ '20', '21', '22' ]
  1188. ] ) );
  1189. } );
  1190. it( 'should navigate to the cell above', () => {
  1191. setModelData( model, modelTable( [
  1192. [ '00', '01', '02' ],
  1193. [ '10', `<image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  1194. [ '20', '21', '22' ]
  1195. ] ) );
  1196. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1197. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1198. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1199. assertEqualMarkup( getModelData( model ), modelTable( [
  1200. [ '00', '01[]', '02' ],
  1201. [ '10', `<image src="${ imageUrl }"><caption>11</caption></image>`, '12' ],
  1202. [ '20', '21', '22' ]
  1203. ] ) );
  1204. } );
  1205. it( 'should navigate to the cell below', () => {
  1206. setModelData( model, modelTable( [
  1207. [ '00', '01', '02' ],
  1208. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image>`, '12' ],
  1209. [ '20', '21', '22' ]
  1210. ] ) );
  1211. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1212. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1213. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1214. assertEqualMarkup( getModelData( model ), modelTable( [
  1215. [ '00', '01', '02' ],
  1216. [ '10', `<image src="${ imageUrl }"><caption>11</caption></image>`, '12' ],
  1217. [ '20', '[]21', '22' ]
  1218. ] ) );
  1219. } );
  1220. } );
  1221. describe( 'horizontal line as only cell content (widget without $text positions)', () => {
  1222. beforeEach( () => {
  1223. setModelData( model, modelTable( [
  1224. [ '00', '01', '02' ],
  1225. [ '10', '[<horizontalLine></horizontalLine>]', '12' ],
  1226. [ '20', '21', '22' ]
  1227. ] ) );
  1228. } );
  1229. it( 'should navigate to the cell on the left', () => {
  1230. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1231. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1232. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1233. assertEqualMarkup( getModelData( model ), modelTable( [
  1234. [ '00', '01', '02' ],
  1235. [ '10[]', '<horizontalLine></horizontalLine>', '12' ],
  1236. [ '20', '21', '22' ]
  1237. ] ) );
  1238. } );
  1239. it( 'should navigate to the cell on the right', () => {
  1240. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1241. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1242. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1243. assertEqualMarkup( getModelData( model ), modelTable( [
  1244. [ '00', '01', '02' ],
  1245. [ '10', '<horizontalLine></horizontalLine>', '[]12' ],
  1246. [ '20', '21', '22' ]
  1247. ] ) );
  1248. } );
  1249. it( 'should navigate to the cell above', () => {
  1250. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1251. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1252. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1253. assertEqualMarkup( getModelData( model ), modelTable( [
  1254. [ '00', '01[]', '02' ],
  1255. [ '10', '<horizontalLine></horizontalLine>', '12' ],
  1256. [ '20', '21', '22' ]
  1257. ] ) );
  1258. } );
  1259. it( 'should navigate to the cell below', () => {
  1260. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1261. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1262. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1263. assertEqualMarkup( getModelData( model ), modelTable( [
  1264. [ '00', '01', '02' ],
  1265. [ '10', '<horizontalLine></horizontalLine>', '12' ],
  1266. [ '20', '[]21', '22' ]
  1267. ] ) );
  1268. } );
  1269. } );
  1270. describe( 'two horizontal lines as only cell content (widget without $text positions)', () => {
  1271. it( 'should navigate to the cell on the left', () => {
  1272. setModelData( model, modelTable( [
  1273. [ '00', '01', '02' ],
  1274. [ '10', '[<horizontalLine></horizontalLine>]<horizontalLine></horizontalLine>', '12' ],
  1275. [ '20', '21', '22' ]
  1276. ] ) );
  1277. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1278. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1279. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1280. assertEqualMarkup( getModelData( model ), modelTable( [
  1281. [ '00', '01', '02' ],
  1282. [ '10[]', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '12' ],
  1283. [ '20', '21', '22' ]
  1284. ] ) );
  1285. } );
  1286. it( 'should navigate to the cell on the right', () => {
  1287. setModelData( model, modelTable( [
  1288. [ '00', '01', '02' ],
  1289. [ '10', '<horizontalLine></horizontalLine>[<horizontalLine></horizontalLine>]', '12' ],
  1290. [ '20', '21', '22' ]
  1291. ] ) );
  1292. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1293. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1294. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1295. assertEqualMarkup( getModelData( model ), modelTable( [
  1296. [ '00', '01', '02' ],
  1297. [ '10', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '[]12' ],
  1298. [ '20', '21', '22' ]
  1299. ] ) );
  1300. } );
  1301. it( 'should navigate to the cell above', () => {
  1302. setModelData( model, modelTable( [
  1303. [ '00', '01', '02' ],
  1304. [ '10', '[<horizontalLine></horizontalLine>]<horizontalLine></horizontalLine>', '12' ],
  1305. [ '20', '21', '22' ]
  1306. ] ) );
  1307. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1308. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1309. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1310. assertEqualMarkup( getModelData( model ), modelTable( [
  1311. [ '00', '01[]', '02' ],
  1312. [ '10', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '12' ],
  1313. [ '20', '21', '22' ]
  1314. ] ) );
  1315. } );
  1316. it( 'should navigate to the cell below', () => {
  1317. setModelData( model, modelTable( [
  1318. [ '00', '01', '02' ],
  1319. [ '10', '<horizontalLine></horizontalLine>[<horizontalLine></horizontalLine>]', '12' ],
  1320. [ '20', '21', '22' ]
  1321. ] ) );
  1322. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1323. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1324. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1325. assertEqualMarkup( getModelData( model ), modelTable( [
  1326. [ '00', '01', '02' ],
  1327. [ '10', '<horizontalLine></horizontalLine><horizontalLine></horizontalLine>', '12' ],
  1328. [ '20', '[]21', '22' ]
  1329. ] ) );
  1330. } );
  1331. } );
  1332. } );
  1333. describe( 'with selection not at the edge of a cell', () => {
  1334. let editorElement, editor, model, styleElement;
  1335. beforeEach( async () => {
  1336. editorElement = global.document.createElement( 'div' );
  1337. global.document.body.appendChild( editorElement );
  1338. editor = await ClassicTestEditor.create( editorElement, {
  1339. plugins: [ Table, Paragraph, Image, ImageCaption, HorizontalLine ]
  1340. } );
  1341. model = editor.model;
  1342. styleElement = global.document.createElement( 'style' );
  1343. styleElement.type = 'text/css';
  1344. styleElement.appendChild( global.document.createTextNode(
  1345. `
  1346. * {
  1347. font-size: 12px !important;
  1348. font-family: serif !important;
  1349. margin: 0 !important;
  1350. padding: 0 !important;
  1351. border: 0 !important
  1352. }
  1353. td { width: 30px !important; }
  1354. tr:nth-child(2) td:nth-child(2) { width: 300px !important; }
  1355. `
  1356. ) );
  1357. global.document.querySelector( 'head' ).appendChild( styleElement );
  1358. } );
  1359. afterEach( async () => {
  1360. editorElement.remove();
  1361. styleElement.remove();
  1362. await editor.destroy();
  1363. } );
  1364. describe( 'simple cell text content', () => {
  1365. it( 'should not navigate to the cell on the left', () => {
  1366. setModelData( model, modelTable( [
  1367. [ '00', '01', '02' ],
  1368. [ '10', '1[]1', '12' ],
  1369. [ '20', '21', '22' ]
  1370. ] ) );
  1371. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1372. sinon.assert.notCalled( leftArrowDomEvtDataStub.preventDefault );
  1373. sinon.assert.notCalled( leftArrowDomEvtDataStub.stopPropagation );
  1374. } );
  1375. it( 'should not navigate to the cell on the right', () => {
  1376. setModelData( model, modelTable( [
  1377. [ '00', '01', '02' ],
  1378. [ '10', '1[]1', '12' ],
  1379. [ '20', '21', '22' ]
  1380. ] ) );
  1381. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1382. sinon.assert.notCalled( rightArrowDomEvtDataStub.preventDefault );
  1383. sinon.assert.notCalled( rightArrowDomEvtDataStub.stopPropagation );
  1384. } );
  1385. it( 'should not navigate to the cell above', () => {
  1386. setModelData( model, modelTable( [
  1387. [ '00', '01', '02' ],
  1388. [ '10', '1[]1', '12' ],
  1389. [ '20', '21', '22' ]
  1390. ] ) );
  1391. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1392. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1393. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1394. assertEqualMarkup( getModelData( model ), modelTable( [
  1395. [ '00', '01', '02' ],
  1396. [ '10', '[]11', '12' ],
  1397. [ '20', '21', '22' ]
  1398. ] ) );
  1399. } );
  1400. it( 'should not navigate to the cell below', () => {
  1401. setModelData( model, modelTable( [
  1402. [ '00', '01', '02' ],
  1403. [ '10', '1[]1', '12' ],
  1404. [ '20', '21', '22' ]
  1405. ] ) );
  1406. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1407. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1408. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1409. assertEqualMarkup( getModelData( model ), modelTable( [
  1410. [ '00', '01', '02' ],
  1411. [ '10', '11[]', '12' ],
  1412. [ '20', '21', '22' ]
  1413. ] ) );
  1414. } );
  1415. } );
  1416. describe( 'selection inside paragraph', () => {
  1417. const text = new Array( 20 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  1418. it( 'should not navigate if caret is in the middle line of a text', () => {
  1419. setModelData( model, modelTable( [
  1420. [ '00', '01', '02' ],
  1421. [ '10', text + '[] ' + text, '12' ],
  1422. [ '20', '21', '22' ]
  1423. ] ) );
  1424. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1425. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  1426. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  1427. } );
  1428. it( 'should move caret to beginning of cell content if caret is in the first line of a text', () => {
  1429. setModelData( model, modelTable( [
  1430. [ '00', '01', '02' ],
  1431. [ '10', 'word[] word' + text, '12' ],
  1432. [ '20', '21', '22' ]
  1433. ] ) );
  1434. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1435. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1436. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1437. assertEqualMarkup( getModelData( model ), modelTable( [
  1438. [ '00', '01', '02' ],
  1439. [ '10', '[]word word' + text, '12' ],
  1440. [ '20', '21', '22' ]
  1441. ] ) );
  1442. } );
  1443. it( 'should move caret to end of cell content if caret is in the last line of a text', () => {
  1444. setModelData( model, modelTable( [
  1445. [ '00', '01', '02' ],
  1446. [ '10', text + 'word[] word', '12' ],
  1447. [ '20', '21', '22' ]
  1448. ] ) );
  1449. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1450. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1451. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1452. assertEqualMarkup( getModelData( model ), modelTable( [
  1453. [ '00', '01', '02' ],
  1454. [ '10', text + 'word word[]', '12' ],
  1455. [ '20', '21', '22' ]
  1456. ] ) );
  1457. } );
  1458. } );
  1459. if ( !env.isGecko ) {
  1460. // This tests fails on Travis. They work correctly when started on local machine.
  1461. // Issue is probably related to text rendering and wrapping.
  1462. describe( 'with selection in the wrap area', () => {
  1463. const text = new Array( 10 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  1464. it( 'should move caret to end if caret is after the last space in the line next to the last one', () => {
  1465. // This is also first position in the last line.
  1466. setModelData( model, modelTable( [
  1467. [ '00', '01', '02' ],
  1468. [ '10', text + ' []word word word', '12' ],
  1469. [ '20', '21', '22' ]
  1470. ] ) );
  1471. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1472. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1473. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1474. assertEqualMarkup( getModelData( model ), modelTable( [
  1475. [ '00', '01', '02' ],
  1476. [ '10', text + ' word word word[]', '12' ],
  1477. [ '20', '21', '22' ]
  1478. ] ) );
  1479. } );
  1480. it( 'should move caret to end if caret is at the last space in the line next to last one', () => {
  1481. setModelData( model, modelTable( [
  1482. [ '00', '01', '02' ],
  1483. [ '10', text + '[] word word word', '12' ],
  1484. [ '20', '21', '22' ]
  1485. ] ) );
  1486. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1487. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1488. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1489. assertEqualMarkup( getModelData( model ), modelTable( [
  1490. [ '00', '01', '02' ],
  1491. [ '10', text + ' word word word[]', '12' ],
  1492. [ '20', '21', '22' ]
  1493. ] ) );
  1494. } );
  1495. it( 'should not move caret if it\'s just before the last space in the line next to last one', () => {
  1496. setModelData( model, modelTable( [
  1497. [ '00', '01', '02' ],
  1498. [ '10', text.substring( 0, text.length - 1 ) + '[]d word word word', '12' ],
  1499. [ '20', '21', '22' ]
  1500. ] ) );
  1501. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1502. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  1503. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  1504. } );
  1505. } );
  1506. }
  1507. describe( 'with multiple paragraphs of text', () => {
  1508. const text = new Array( 100 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  1509. it( 'should not navigate if caret is in the middle line of a text', () => {
  1510. setModelData( model, modelTable( [
  1511. [ '00', '01', '02' ],
  1512. [ '10', `<paragraph>${ text }[]${ text }</paragraph><paragraph>foobar</paragraph>`, '12' ],
  1513. [ '20', '21', '22' ]
  1514. ] ) );
  1515. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1516. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  1517. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  1518. } );
  1519. it( 'should move caret to beginning of cell content if caret is in the first line of a text', () => {
  1520. setModelData( model, modelTable( [
  1521. [ '00', '01', '02' ],
  1522. [ '10', `<paragraph>word[]${ text }</paragraph><paragraph>foobar</paragraph>`, '12' ],
  1523. [ '20', '21', '22' ]
  1524. ] ) );
  1525. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1526. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1527. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1528. assertEqualMarkup( getModelData( model ), modelTable( [
  1529. [ '00', '01', '02' ],
  1530. [ '10', `<paragraph>[]word${ text }</paragraph><paragraph>foobar</paragraph>`, '12' ],
  1531. [ '20', '21', '22' ]
  1532. ] ) );
  1533. } );
  1534. it( 'should not move caret to end of cell content if caret is not last line of text', () => {
  1535. setModelData( model, modelTable( [
  1536. [ '00', '01', '02' ],
  1537. [ '10', `<paragraph>${ text }word []word</paragraph><paragraph>foobar</paragraph>`, '12' ],
  1538. [ '20', '21', '22' ]
  1539. ] ) );
  1540. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1541. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  1542. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  1543. } );
  1544. it( 'should move caret to end of cell content if caret is in the last line of a text', () => {
  1545. setModelData( model, modelTable( [
  1546. [ '00', '01', '02' ],
  1547. [ '10', `<paragraph>foobar</paragraph><paragraph>${ text }word []word</paragraph>`, '12' ],
  1548. [ '20', '21', '22' ]
  1549. ] ) );
  1550. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1551. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1552. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1553. assertEqualMarkup( getModelData( model ), modelTable( [
  1554. [ '00', '01', '02' ],
  1555. [ '10', `<paragraph>foobar</paragraph><paragraph>${ text }word word[]</paragraph>`, '12' ],
  1556. [ '20', '21', '22' ]
  1557. ] ) );
  1558. } );
  1559. } );
  1560. describe( 'with horizontal line widget', () => {
  1561. const text = new Array( 100 ).fill( 0 ).map( () => 'word' ).join( ' ' );
  1562. it( 'should not navigate if caret is in the middle line of a text', () => {
  1563. setModelData( model, modelTable( [
  1564. [ '00', '01', '02' ],
  1565. [ '10', `<horizontalLine></horizontalLine><paragraph>${ text }[]${ text }</paragraph>`, '12' ],
  1566. [ '20', '21', '22' ]
  1567. ] ) );
  1568. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1569. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  1570. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  1571. } );
  1572. it( 'should move caret to beginning of cell content if caret is in the first line of a text', () => {
  1573. setModelData( model, modelTable( [
  1574. [ '00', '01', '02' ],
  1575. [ '10', `<horizontalLine></horizontalLine><paragraph>word[] ${ text }</paragraph>`, '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', `[<horizontalLine></horizontalLine>]<paragraph>word ${ text }</paragraph>`, '12' ],
  1584. [ '20', '21', '22' ]
  1585. ] ) );
  1586. } );
  1587. it( 'should move caret to end of cell content if caret is in the last line of a text', () => {
  1588. setModelData( model, modelTable( [
  1589. [ '00', '01', '02' ],
  1590. [ '10', `<paragraph>${ text } word []word</paragraph><horizontalLine></horizontalLine>`, '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', `<paragraph>${ text } word word</paragraph>[<horizontalLine></horizontalLine>]`, '12' ],
  1599. [ '20', '21', '22' ]
  1600. ] ) );
  1601. } );
  1602. it( 'should not move caret to end of cell content if widget is selected in middle of cell content', () => {
  1603. const paragraph = `<paragraph>${ text }</paragraph>`;
  1604. const hr = '<horizontalLine></horizontalLine>';
  1605. setModelData( model, modelTable( [
  1606. [ '00', '01', '02' ],
  1607. [ '10', `${ paragraph }[${ hr }]${ paragraph }${ hr }`, '12' ],
  1608. [ '20', '21', '22' ]
  1609. ] ) );
  1610. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1611. assertEqualMarkup( getModelData( model ), modelTable( [
  1612. [ '00', '01', '02' ],
  1613. [ '10', `${ paragraph }${ hr }<paragraph>[]${ text }</paragraph>${ hr }`, '12' ],
  1614. [ '20', '21', '22' ]
  1615. ] ) );
  1616. } );
  1617. it( 'should not move caret to end of cell content if widget is next to selection', () => {
  1618. const paragraph = `<paragraph>${ text }</paragraph>`;
  1619. const hr = '<horizontalLine></horizontalLine>';
  1620. setModelData( model, modelTable( [
  1621. [ '00', '01', '02' ],
  1622. [ '10', `${ paragraph }[]${ hr }`, '12' ],
  1623. [ '20', '21', '22' ]
  1624. ] ) );
  1625. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1626. assertEqualMarkup( getModelData( model ), modelTable( [
  1627. [ '00', '01', '02' ],
  1628. [ '10', `${ paragraph }[${ hr }]`, '12' ],
  1629. [ '20', '21', '22' ]
  1630. ] ) );
  1631. } );
  1632. } );
  1633. describe( 'contains image widget with caption and selection inside the caption', () => {
  1634. it( 'should not navigate to the cell on the left', () => {
  1635. setModelData( model, modelTable( [
  1636. [ '00', '01', '02' ],
  1637. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>[]11</caption></image>`, '12' ],
  1638. [ '20', '21', '22' ]
  1639. ] ) );
  1640. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1641. sinon.assert.notCalled( leftArrowDomEvtDataStub.preventDefault );
  1642. sinon.assert.notCalled( leftArrowDomEvtDataStub.stopPropagation );
  1643. } );
  1644. it( 'should not navigate to the cell on the right', () => {
  1645. setModelData( model, modelTable( [
  1646. [ '00', '01', '02' ],
  1647. [ '10', `<image src="${ imageUrl }"><caption>11[]</caption></image><paragraph>foo</paragraph>`, '12' ],
  1648. [ '20', '21', '22' ]
  1649. ] ) );
  1650. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1651. sinon.assert.notCalled( rightArrowDomEvtDataStub.preventDefault );
  1652. sinon.assert.notCalled( rightArrowDomEvtDataStub.stopPropagation );
  1653. } );
  1654. it( 'should not navigate to the cell above', () => {
  1655. setModelData( model, modelTable( [
  1656. [ '00', '01', '02' ],
  1657. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>1[]1</caption></image>`, '12' ],
  1658. [ '20', '21', '22' ]
  1659. ] ) );
  1660. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1661. sinon.assert.notCalled( upArrowDomEvtDataStub.preventDefault );
  1662. sinon.assert.notCalled( upArrowDomEvtDataStub.stopPropagation );
  1663. } );
  1664. it( 'should not navigate to the cell above but should select image widget', () => {
  1665. setModelData( model, modelTable( [
  1666. [ '00', '01', '02' ],
  1667. [ '10', `<image src="${ imageUrl }"><caption>1[]1</caption></image><paragraph>foo</paragraph>`, '12' ],
  1668. [ '20', '21', '22' ]
  1669. ] ) );
  1670. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1671. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1672. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1673. assertEqualMarkup( getModelData( model ), modelTable( [
  1674. [ '00', '01', '02' ],
  1675. [ '10', `[<image src="${ imageUrl }"><caption>11</caption></image>]<paragraph>foo</paragraph>`, '12' ],
  1676. [ '20', '21', '22' ]
  1677. ] ) );
  1678. } );
  1679. it( 'should not navigate to the cell below when followed by paragraph', () => {
  1680. setModelData( model, modelTable( [
  1681. [ '00', '01', '02' ],
  1682. [ '10', `<image src="${ imageUrl }"><caption>1[]1</caption></image><paragraph>foo</paragraph>`, '12' ],
  1683. [ '20', '21', '22' ]
  1684. ] ) );
  1685. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1686. sinon.assert.notCalled( downArrowDomEvtDataStub.preventDefault );
  1687. sinon.assert.notCalled( downArrowDomEvtDataStub.stopPropagation );
  1688. } );
  1689. it( 'should not navigate to the cell below but should select image widget', () => {
  1690. setModelData( model, modelTable( [
  1691. [ '00', '01', '02' ],
  1692. [ '10', `<paragraph>foo</paragraph><image src="${ imageUrl }"><caption>1[]1</caption></image>`, '12' ],
  1693. [ '20', '21', '22' ]
  1694. ] ) );
  1695. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1696. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1697. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1698. assertEqualMarkup( getModelData( model ), modelTable( [
  1699. [ '00', '01', '02' ],
  1700. [ '10', `<paragraph>foo</paragraph>[<image src="${ imageUrl }"><caption>11</caption></image>]`, '12' ],
  1701. [ '20', '21', '22' ]
  1702. ] ) );
  1703. } );
  1704. it( 'should not navigate to the cell above but should select image widget without caption', () => {
  1705. setModelData( model, modelTable( [
  1706. [ '00', '01', '02' ],
  1707. [ '10', `<image src="${ imageUrl }"><caption></caption></image><paragraph>f[]oo</paragraph>`, '12' ],
  1708. [ '20', '21', '22' ]
  1709. ] ) );
  1710. editor.editing.view.document.fire( 'keydown', upArrowDomEvtDataStub );
  1711. sinon.assert.calledOnce( upArrowDomEvtDataStub.preventDefault );
  1712. sinon.assert.calledOnce( upArrowDomEvtDataStub.stopPropagation );
  1713. assertEqualMarkup( getModelData( model ), modelTable( [
  1714. [ '00', '01', '02' ],
  1715. [ '10', `[<image src="${ imageUrl }"><caption></caption></image>]<paragraph>foo</paragraph>`, '12' ],
  1716. [ '20', '21', '22' ]
  1717. ] ) );
  1718. } );
  1719. it( 'should not navigate to the cell below but should select image widget without caption', () => {
  1720. setModelData( model, modelTable( [
  1721. [ '00', '01', '02' ],
  1722. [ '10', `<paragraph>f[]oo</paragraph><image src="${ imageUrl }"><caption></caption></image>`, '12' ],
  1723. [ '20', '21', '22' ]
  1724. ] ) );
  1725. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1726. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1727. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1728. assertEqualMarkup( getModelData( model ), modelTable( [
  1729. [ '00', '01', '02' ],
  1730. [ '10', `<paragraph>foo</paragraph>[<image src="${ imageUrl }"><caption></caption></image>]`, '12' ],
  1731. [ '20', '21', '22' ]
  1732. ] ) );
  1733. } );
  1734. } );
  1735. } );
  1736. } );
  1737. describe( 'for right-to-left content language', () => {
  1738. beforeEach( () => {
  1739. return VirtualTestEditor
  1740. .create( {
  1741. plugins: [ TableEditing, TableNavigation, TableSelection, Paragraph, ImageEditing, MediaEmbedEditing ],
  1742. language: 'ar'
  1743. } )
  1744. .then( newEditor => {
  1745. editor = newEditor;
  1746. model = editor.model;
  1747. modelRoot = model.document.getRoot();
  1748. tableSelection = editor.plugins.get( TableSelection );
  1749. } );
  1750. } );
  1751. describe( 'with the table cell selected from outside', () => {
  1752. beforeEach( () => {
  1753. setModelData( model, modelTable( [
  1754. [ '00', '01', '02' ],
  1755. [ '10', '11', '12' ],
  1756. [ '20', '21', '22' ]
  1757. ] ) );
  1758. tableSelection._setCellSelection(
  1759. modelRoot.getNodeByPath( [ 0, 1, 1 ] ),
  1760. modelRoot.getNodeByPath( [ 0, 1, 1 ] )
  1761. );
  1762. } );
  1763. it( 'should move to the cell on the right (it\'s visually flipped by browser)', () => {
  1764. editor.editing.view.document.fire( 'keydown', leftArrowDomEvtDataStub );
  1765. sinon.assert.calledOnce( leftArrowDomEvtDataStub.preventDefault );
  1766. sinon.assert.calledOnce( leftArrowDomEvtDataStub.stopPropagation );
  1767. assertEqualMarkup( getModelData( model ), modelTable( [
  1768. [ '00', '01', '02' ],
  1769. [ '10', '11', '[]12' ],
  1770. [ '20', '21', '22' ]
  1771. ] ) );
  1772. } );
  1773. it( 'should move to the cell on the left (it\'s visually flipped by browser)', () => {
  1774. editor.editing.view.document.fire( 'keydown', rightArrowDomEvtDataStub );
  1775. sinon.assert.calledOnce( rightArrowDomEvtDataStub.preventDefault );
  1776. sinon.assert.calledOnce( rightArrowDomEvtDataStub.stopPropagation );
  1777. assertEqualMarkup( getModelData( model ), modelTable( [
  1778. [ '00', '01', '02' ],
  1779. [ '10[]', '11', '12' ],
  1780. [ '20', '21', '22' ]
  1781. ] ) );
  1782. } );
  1783. it( 'should move to the cell above selection', () => {
  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 move to the cell below selection', () => {
  1794. editor.editing.view.document.fire( 'keydown', downArrowDomEvtDataStub );
  1795. sinon.assert.calledOnce( downArrowDomEvtDataStub.preventDefault );
  1796. sinon.assert.calledOnce( downArrowDomEvtDataStub.stopPropagation );
  1797. assertEqualMarkup( getModelData( model ), modelTable( [
  1798. [ '00', '01', '02' ],
  1799. [ '10', '11', '12' ],
  1800. [ '20', '[]21', '22' ]
  1801. ] ) );
  1802. } );
  1803. } );
  1804. } );
  1805. } );
  1806. } );