66e9b9e4db4263a79776463683aac71bbf75dc9ea6172926f2e001eec7bf3e33850baee85518a20ef194eb034edc7904d4283032136bdf1b0a723e5bec1e69 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768
  1. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  2. describe('ColumnSorting', function () {
  3. var id = 'testContainer';
  4. beforeEach(function () {
  5. this.$container = $('<div id="' + id + '" style="overflow: auto; width: 300px; height: 200px;"></div>').appendTo('body');
  6. this.sortByColumn = function (columnIndex) {
  7. var element = this.$container.find('th span.columnSorting:eq(' + columnIndex + ')');
  8. element.simulate('mousedown');
  9. element.simulate('mouseup');
  10. };
  11. });
  12. afterEach(function () {
  13. if (this.$container) {
  14. destroy();
  15. this.$container.remove();
  16. }
  17. });
  18. var arrayOfObjects = function arrayOfObjects() {
  19. return [{ id: 1, name: 'Ted', lastName: 'Right' }, { id: 2, name: 'Frank', lastName: 'Honest' }, { id: 3, name: 'Joan', lastName: 'Well' }, { id: 4, name: 'Sid', lastName: 'Strong' }, { id: 5, name: 'Jane', lastName: 'Neat' }, { id: 6, name: 'Chuck', lastName: 'Jackson' }, { id: 7, name: 'Meg', lastName: 'Jansen' }, { id: 8, name: 'Rob', lastName: 'Norris' }, { id: 9, name: 'Sean', lastName: 'O\'Hara' }, { id: 10, name: 'Eve', lastName: 'Branson' }];
  20. };
  21. it('should sort table by first visible column', function () {
  22. var hot = handsontable({
  23. data: [[1, 9, 3, 4, 5, 6, 7, 8, 9], [9, 8, 7, 6, 5, 4, 3, 2, 1], [8, 7, 6, 5, 4, 3, 3, 1, 9], [0, 3, 0, 5, 6, 7, 8, 9, 1]],
  24. colHeaders: true,
  25. columnSorting: true
  26. });
  27. var htCore = getHtCore();
  28. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  29. expect(htCore.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('9');
  30. expect(htCore.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('3');
  31. expect(htCore.find('tbody tr:eq(0) td:eq(3)').text()).toEqual('4');
  32. this.sortByColumn(0);
  33. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  34. expect(htCore.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('3');
  35. expect(htCore.find('tbody tr:eq(0) td:eq(2)').text()).toEqual('0');
  36. expect(htCore.find('tbody tr:eq(0) td:eq(3)').text()).toEqual('5');
  37. });
  38. it('should apply stable sort function #3606', function () {
  39. var hot = handsontable({
  40. data: [['mercedes1', 'Mercedes', 'A 160', '01/14/2007'], ['citroen1', 'Citroen', 'C4 Coupe', '12/01/2007'], ['opel1', 'Opel', 'Astra', '02/02/2006'], ['bmw1', 'BMW', '320i Coupe', '07/24/2009'], ['citroen2', 'Citroen', 'C4 Coupe', '12/01/2012'], ['opel2', 'Opel', 'Astra', '02/02/2004'], ['mercedes2', 'Mercedes', 'A 160', '01/14/2008'], ['citroen3', 'Citroen', 'C4 Coupe', '12/01/2007'], ['mercedes3', 'Mercedes', 'A 160', '01/14/2009'], ['opel3', 'Opel', 'Astra', '02/02/2006'], ['bmw2', 'BMW', '320i Coupe', '07/24/2013'], ['bmw3', 'BMW', '320i Coupe', '07/24/2012']],
  41. columns: [{}, {}, {
  42. type: 'date',
  43. dateFormat: 'mm/dd/yy'
  44. }, {
  45. type: 'numeric'
  46. }],
  47. columnSorting: true
  48. });
  49. hot.sort(1, true); // ASC
  50. expect(hot.getDataAtCol(0)).toEqual(['bmw1', 'bmw2', 'bmw3', 'citroen1', 'citroen2', 'citroen3', 'mercedes1', 'mercedes2', 'mercedes3', 'opel1', 'opel2', 'opel3']);
  51. hot.sort(1, false); // DESC
  52. expect(hot.getDataAtCol(0)).toEqual(['opel1', 'opel2', 'opel3', 'mercedes1', 'mercedes2', 'mercedes3', 'citroen1', 'citroen2', 'citroen3', 'bmw1', 'bmw2', 'bmw3']);
  53. });
  54. it('should not throw error when trying run handsontable with columnSorting and autoRowSize in the same time.', function () {
  55. var errors = 0;
  56. try {
  57. handsontable({
  58. data: arrayOfObjects(),
  59. autoRowSize: true,
  60. columnSorting: true
  61. });
  62. } catch (e) {
  63. errors++;
  64. }
  65. expect(errors).toBe(0);
  66. });
  67. it('should sort numbers descending after 2 clicks on table header', function () {
  68. handsontable({
  69. data: arrayOfObjects(),
  70. colHeaders: true,
  71. columnSorting: true
  72. });
  73. this.sortByColumn(0);
  74. this.sortByColumn(0);
  75. expect(this.$container.find('tr td').first().html()).toEqual('10');
  76. });
  77. it('should remove specified row from sorted table and NOT sort the table again', function () {
  78. var hot = handsontable({
  79. data: [[1, 'B'], [3, 'D'], [2, 'A'], [0, 'C']],
  80. colHeaders: true,
  81. columnSorting: true
  82. });
  83. this.sortByColumn(0);
  84. var htCore = getHtCore();
  85. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  86. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  87. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  88. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  89. expect(htCore.find('tbody tr').length).toEqual(4);
  90. // Now if sort is launched, sorting ordered will be reversed
  91. hot.sortOrder = false;
  92. hot.alter('remove_row', 0);
  93. expect(htCore.find('tbody tr').length).toEqual(3);
  94. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  95. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  96. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  97. });
  98. it('should add an empty row to sorted table', function () {
  99. var hot = handsontable({
  100. data: [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']],
  101. colHeaders: true,
  102. columnSorting: true
  103. });
  104. this.sortByColumn(0);
  105. var htCore = getHtCore();
  106. expect(htCore.find('tbody tr').length).toEqual(4);
  107. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  108. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  109. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  110. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  111. hot.alter('insert_row', 1, 2);
  112. expect(htCore.find('tbody tr').length).toEqual(6);
  113. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  114. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('');
  115. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  116. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('1');
  117. expect(htCore.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('2');
  118. expect(htCore.find('tbody tr:eq(5) td:eq(0)').text()).toEqual('3');
  119. });
  120. it('should add an empty row to sorted table at a given index', function () {
  121. var hot = handsontable({
  122. data: [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']],
  123. colHeaders: true,
  124. columnSorting: true
  125. });
  126. var htCore = getHtCore();
  127. this.sortByColumn(0);
  128. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  129. expect(htCore.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('');
  130. hot.alter('insert_row', 2);
  131. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  132. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  133. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  134. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  135. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('');
  136. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  137. });
  138. it('should NOT sort the table after value update in sorted column', function () {
  139. var hot = handsontable({
  140. data: [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']],
  141. colHeaders: true,
  142. columnSorting: true
  143. });
  144. var htCore = getHtCore();
  145. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  146. this.sortByColumn(0);
  147. this.sortByColumn(0);
  148. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  149. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('2');
  150. hot.setDataAtCell(1, 0, 20);
  151. render();
  152. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  153. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('20');
  154. });
  155. it('defaultSort comparing function shouldn\'t change order when comparing empty string, null and undefined', function () {
  156. var hot = handsontable({});
  157. var defaultSort = hot.getPlugin('columnSorting').defaultSort;
  158. expect(defaultSort(false, {})(['key1', null], ['key2', null])).toEqual(0);
  159. expect(defaultSort(false, {})(['key1', ''], ['key2', ''])).toEqual(0);
  160. expect(defaultSort(false, {})(['key1', undefined], ['key2', undefined])).toEqual(0);
  161. expect(defaultSort(false, {})(['key1', ''], ['key2', null])).toEqual(0);
  162. expect(defaultSort(false, {})(['key1', null], ['key2', ''])).toEqual(0);
  163. expect(defaultSort(false, {})(['key1', ''], ['key2', undefined])).toEqual(0);
  164. expect(defaultSort(false, {})(['key1', undefined], ['key2', ''])).toEqual(0);
  165. expect(defaultSort(false, {})(['key1', null], ['key2', undefined])).toEqual(0);
  166. expect(defaultSort(false, {})(['key1', undefined], ['key2', null])).toEqual(0);
  167. });
  168. it('should place empty strings, null and undefined values at proper position (stability of default comparing function)', function () {
  169. var hot = handsontable({
  170. data: [[null, 'Ted Right'], [undefined, 'Jane Neat'], [null, 'Meg Jansen'], ['', 'Sean Hara'], ['', 'Eve Branson'], [6, 'Frank Honest'], [7, 'Joan Well'], [8, 'Sid Strong'], [9, 'Chuck Jackson'], [10, 'Rob Norris'], [11, 'Eve Well']],
  171. columnSorting: true
  172. });
  173. hot.sort(0, true); // ASC
  174. expect(hot.getDataAtCol(1)).toEqual(['Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris', 'Eve Well',
  175. // empty cells below
  176. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  177. hot.sort(0, false); // DESC
  178. expect(hot.getDataAtCol(1)).toEqual(['Eve Well', 'Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  179. // empty cells below
  180. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  181. });
  182. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` option is enabled ' + '(API call, data type: default)', function () {
  183. var hot = handsontable({
  184. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  185. columnSorting: {
  186. sortEmptyCells: true
  187. }
  188. });
  189. hot.sort(0, true); // ASC
  190. expect(hot.getDataAtCol(1)).toEqual(['Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson',
  191. // empty cells above
  192. 'Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris']);
  193. hot.sort(0, false); // DESC
  194. expect(hot.getDataAtCol(1)).toEqual(['Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  195. // empty cells below
  196. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  197. });
  198. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` ' + 'option is enabled and `column` property of `columnSorting` option is set (data type: default)', function () {
  199. var hot = handsontable({
  200. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  201. columnSorting: {
  202. sortEmptyCells: true,
  203. sortOrder: true,
  204. column: 0
  205. }
  206. });
  207. // ASC
  208. expect(hot.getDataAtCol(1)).toEqual(['Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson',
  209. // empty cells above
  210. 'Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris']);
  211. if (this.$container) {
  212. destroy();
  213. this.$container.remove();
  214. }
  215. hot = handsontable({
  216. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  217. columnSorting: {
  218. sortEmptyCells: true,
  219. sortOrder: false,
  220. column: 0
  221. }
  222. });
  223. // DESC
  224. expect(hot.getDataAtCol(1)).toEqual(['Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  225. // empty cells below
  226. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  227. });
  228. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` ' + 'option is enabled and `column` property of `columnSorting` option is set (data type: numeric)', function () {
  229. var hot = handsontable({
  230. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  231. columns: [{
  232. type: 'numeric'
  233. }, {}],
  234. columnSorting: {
  235. sortEmptyCells: true,
  236. sortOrder: true,
  237. column: 0
  238. }
  239. });
  240. // ASC
  241. expect(hot.getDataAtCol(1)).toEqual(['Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson',
  242. // empty cells above
  243. 'Frank Honest', 'Joan Well', 'Sid Strong', 'Chuck Jackson', 'Rob Norris']);
  244. if (this.$container) {
  245. destroy();
  246. this.$container.remove();
  247. }
  248. hot = handsontable({
  249. data: [[6, 'Frank Honest'], [null, 'Ted Right'], [7, 'Joan Well'], [8, 'Sid Strong'], [undefined, 'Jane Neat'], [9, 'Chuck Jackson'], [null, 'Meg Jansen'], [10, 'Rob Norris'], ['', 'Sean Hara'], ['', 'Eve Branson']],
  250. columnSorting: {
  251. sortEmptyCells: true,
  252. sortOrder: false,
  253. column: 0
  254. }
  255. });
  256. // DESC
  257. expect(hot.getDataAtCol(1)).toEqual(['Rob Norris', 'Chuck Jackson', 'Sid Strong', 'Joan Well', 'Frank Honest',
  258. // empty cells below
  259. 'Ted Right', 'Jane Neat', 'Meg Jansen', 'Sean Hara', 'Eve Branson']);
  260. });
  261. describe('data type: date', function () {
  262. it('dateSort comparing function shouldn\'t change order when comparing empty string, null and undefined', function () {
  263. var hot = handsontable({});
  264. var dateSort = hot.getPlugin('columnSorting').dateSort;
  265. expect(dateSort(false, {})(['key1', null], ['key2', null])).toEqual(0);
  266. expect(dateSort(false, {})(['key1', ''], ['key2', ''])).toEqual(0);
  267. expect(dateSort(false, {})(['key1', undefined], ['key2', undefined])).toEqual(0);
  268. expect(dateSort(false, {})(['key1', ''], ['key2', null])).toEqual(0);
  269. expect(dateSort(false, {})(['key1', null], ['key2', ''])).toEqual(0);
  270. expect(dateSort(false, {})(['key1', ''], ['key2', undefined])).toEqual(0);
  271. expect(dateSort(false, {})(['key1', undefined], ['key2', ''])).toEqual(0);
  272. expect(dateSort(false, {})(['key1', null], ['key2', undefined])).toEqual(0);
  273. expect(dateSort(false, {})(['key1', undefined], ['key2', null])).toEqual(0);
  274. });
  275. it('should place empty strings, null and undefined values at proper position when `sortEmptyCells` ' + 'option is enabled and `column` property of `columnSorting` option is set', function () {
  276. var hot = handsontable({
  277. data: [['Citroen1', 'C4 Coupe', null], ['Mercedes1', 'A 160', '12/01/2008'], ['Mercedes2', 'A 160', '01/14/2006'], ['Citroen2', 'C4 Coupe', undefined], ['Audi1', 'A4 Avant', '11/19/2011'], ['Opel1', 'Astra', '02/02/2004'], ['Citroen3', 'C4 Coupe', null], ['BMW1', '320i Coupe', '07/24/2011'], ['Citroen4', 'C4 Coupe', ''], ['Citroen5', 'C4 Coupe', '']],
  278. columns: [{}, {}, {
  279. type: 'date',
  280. dateFormat: 'MM/DD/YYYY'
  281. }],
  282. columnSorting: {
  283. sortEmptyCells: true,
  284. sortOrder: true,
  285. column: 2
  286. }
  287. });
  288. // ASC
  289. expect(hot.getDataAtCol(0)).toEqual(['Citroen1', 'Citroen2', 'Citroen3', 'Citroen4', 'Citroen5',
  290. // empty cells above
  291. 'Opel1', 'Mercedes2', 'Mercedes1', 'BMW1', 'Audi1']);
  292. if (this.$container) {
  293. destroy();
  294. this.$container.remove();
  295. }
  296. hot = handsontable({
  297. data: [['Citroen1', 'C4 Coupe', null], ['Mercedes1', 'A 160', '12/01/2008'], ['Mercedes2', 'A 160', '01/14/2006'], ['Citroen2', 'C4 Coupe', undefined], ['Audi1', 'A4 Avant', '11/19/2011'], ['Opel1', 'Astra', '02/02/2004'], ['Citroen3', 'C4 Coupe', null], ['BMW1', '320i Coupe', '07/24/2011'], ['Citroen4', 'C4 Coupe', ''], ['Citroen5', 'C4 Coupe', '']],
  298. columns: [{}, {}, {
  299. type: 'date',
  300. dateFormat: 'MM/DD/YYYY'
  301. }],
  302. columnSorting: {
  303. sortEmptyCells: true,
  304. sortOrder: false,
  305. column: 2
  306. }
  307. });
  308. // DESC
  309. expect(hot.getDataAtCol(0)).toEqual(['Audi1', 'BMW1', 'Mercedes1', 'Mercedes2', 'Opel1',
  310. // empty cells below
  311. 'Citroen1', 'Citroen2', 'Citroen3', 'Citroen4', 'Citroen5']);
  312. });
  313. it('should sort date columns (MM/DD/YYYY)', function () {
  314. var hot = handsontable({
  315. data: [['Mercedes', 'A 160', '01/14/2006', 6999.9999], ['Citroen', 'C4 Coupe', '12/01/2008', 8330], ['Audi', 'A4 Avant', '11/19/2011', 33900], ['Opel', 'Astra', '02/02/2004', 7000], ['BMW', '320i Coupe', '07/24/2011', 30500]],
  316. columns: [{}, {}, {
  317. type: 'date',
  318. dateFormat: 'MM/DD/YYYY'
  319. }, {
  320. type: 'numeric'
  321. }],
  322. colHeaders: true,
  323. columnSorting: true
  324. });
  325. hot.sort(2, true); // ASC
  326. expect(hot.getDataAtRow(0)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  327. expect(hot.getDataAtRow(1)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  328. expect(hot.getDataAtRow(2)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  329. expect(hot.getDataAtRow(3)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  330. expect(hot.getDataAtRow(4)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  331. hot.sort(2, false); // DESC
  332. expect(hot.getDataAtRow(0)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  333. expect(hot.getDataAtRow(1)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  334. expect(hot.getDataAtRow(2)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  335. expect(hot.getDataAtRow(3)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  336. expect(hot.getDataAtRow(4)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  337. });
  338. it('should sort date columns (DD/MM/YYYY)', function () {
  339. var hot = handsontable({
  340. data: [['Mercedes', 'A 160', '01/12/2012', 6999.9999], ['Citroen', 'C4 Coupe', '12/01/2013', 8330], ['Audi', 'A4 Avant', '11/10/2014', 33900], ['Opel', 'Astra', '02/02/2015', 7000], ['BMW', '320i Coupe', '07/02/2013', 30500]],
  341. columns: [{}, {}, {
  342. type: 'date',
  343. dateFormat: 'DD/MM/YYYY'
  344. }, {
  345. type: 'numeric'
  346. }],
  347. colHeaders: true,
  348. columnSorting: true
  349. });
  350. hot.sort(2, true); // ASC
  351. expect(hot.getDataAtRow(0)).toEqual(['Mercedes', 'A 160', '01/12/2012', 6999.9999]);
  352. expect(hot.getDataAtRow(1)).toEqual(['Citroen', 'C4 Coupe', '12/01/2013', 8330]);
  353. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/02/2013', 30500]);
  354. expect(hot.getDataAtRow(3)).toEqual(['Audi', 'A4 Avant', '11/10/2014', 33900]);
  355. expect(hot.getDataAtRow(4)).toEqual(['Opel', 'Astra', '02/02/2015', 7000]);
  356. hot.sort(2, false); // DESC
  357. expect(hot.getDataAtRow(0)).toEqual(['Opel', 'Astra', '02/02/2015', 7000]);
  358. expect(hot.getDataAtRow(1)).toEqual(['Audi', 'A4 Avant', '11/10/2014', 33900]);
  359. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/02/2013', 30500]);
  360. expect(hot.getDataAtRow(3)).toEqual(['Citroen', 'C4 Coupe', '12/01/2013', 8330]);
  361. expect(hot.getDataAtRow(4)).toEqual(['Mercedes', 'A 160', '01/12/2012', 6999.9999]);
  362. });
  363. it('should sort date columns (MMMM Do YYYY)', function () {
  364. var hot = handsontable({
  365. data: [['Mercedes', 'A 160', 'October 28th 2016', 6999.9999], ['Citroen', 'C4 Coupe', 'October 27th 2001', 8330], ['Audi', 'A4 Avant', 'July 8th 1999', 33900], ['Opel', 'Astra', 'June 1st 2001', 7000], ['BMW', '320i Coupe', 'August 3rd 2001', 30500]],
  366. columns: [{}, {}, {
  367. type: 'date',
  368. dateFormat: 'MMMM Do YYYY'
  369. }, {
  370. type: 'numeric'
  371. }],
  372. colHeaders: true,
  373. columnSorting: true
  374. });
  375. hot.sort(2, true); // ASC
  376. expect(hot.getDataAtRow(0)).toEqual(['Audi', 'A4 Avant', 'July 8th 1999', 33900]);
  377. expect(hot.getDataAtRow(1)).toEqual(['Opel', 'Astra', 'June 1st 2001', 7000]);
  378. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', 'August 3rd 2001', 30500]);
  379. expect(hot.getDataAtRow(3)).toEqual(['Citroen', 'C4 Coupe', 'October 27th 2001', 8330]);
  380. expect(hot.getDataAtRow(4)).toEqual(['Mercedes', 'A 160', 'October 28th 2016', 6999.9999]);
  381. hot.sort(2, false); // DESC
  382. expect(hot.getDataAtRow(0)).toEqual(['Mercedes', 'A 160', 'October 28th 2016', 6999.9999]);
  383. expect(hot.getDataAtRow(1)).toEqual(['Citroen', 'C4 Coupe', 'October 27th 2001', 8330]);
  384. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', 'August 3rd 2001', 30500]);
  385. expect(hot.getDataAtRow(3)).toEqual(['Opel', 'Astra', 'June 1st 2001', 7000]);
  386. expect(hot.getDataAtRow(4)).toEqual(['Audi', 'A4 Avant', 'July 8th 1999', 33900]);
  387. });
  388. it('should sort date columns along with empty and null values', function () {
  389. var hot = handsontable({
  390. data: [['Mercedes', 'A 160', '01/14/2006', 6999.9999], ['Citroen', 'C4 Coupe', '12/01/2008', 8330], ['Citroen', 'C4 Coupe null', null, 8330], ['Citroen', 'C4 Coupe empty', '', 8330], ['Audi', 'A4 Avant', '11/19/2011', 33900], ['Opel', 'Astra', '02/02/2004', 7000], ['BMW', '320i Coupe', '07/24/2011', 30500]],
  391. columns: [{}, {}, {
  392. type: 'date',
  393. dateFormat: 'mm/dd/yy'
  394. }, {
  395. type: 'numeric'
  396. }],
  397. colHeaders: true,
  398. columnSorting: true
  399. });
  400. hot.sort(2, true); // ASC
  401. expect(hot.getDataAtRow(0)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  402. expect(hot.getDataAtRow(1)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  403. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  404. expect(hot.getDataAtRow(3)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  405. expect(hot.getDataAtRow(4)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  406. hot.sort(2, false); // DESC
  407. expect(hot.getDataAtRow(0)).toEqual(['Citroen', 'C4 Coupe', '12/01/2008', 8330]);
  408. expect(hot.getDataAtRow(1)).toEqual(['Audi', 'A4 Avant', '11/19/2011', 33900]);
  409. expect(hot.getDataAtRow(2)).toEqual(['BMW', '320i Coupe', '07/24/2011', 30500]);
  410. expect(hot.getDataAtRow(3)).toEqual(['Opel', 'Astra', '02/02/2004', 7000]);
  411. expect(hot.getDataAtRow(4)).toEqual(['Mercedes', 'A 160', '01/14/2006', 6999.9999]);
  412. });
  413. });
  414. describe('data type: time', function () {
  415. it('should properly rewrite time into correct format after sort', function (done) {
  416. var hot = handsontable({
  417. data: [['0:00:01 am'], ['5:30:14 pm'], ['8:00:00 pm'], ['11:15:05 am'], ['4:07:48 am']],
  418. columns: [{
  419. type: 'time',
  420. dateFormat: 'h:mm:ss a',
  421. correctFormat: true
  422. }],
  423. colHeaders: true,
  424. columnSorting: {
  425. column: 0,
  426. sortOrder: false
  427. }
  428. });
  429. hot.setDataAtCell(0, 0, '19:55', 'edit');
  430. setTimeout(function () {
  431. expect(hot.getDataAtCell(0, 0)).toEqual('7:55:00 pm');
  432. done();
  433. }, 250);
  434. });
  435. });
  436. it('should properly sort numeric data', function () {
  437. var hot = handsontable({
  438. data: [['Mercedes', 'A 160', '01/14/2006', '6999.9999'], ['Citroen', 'C4 Coupe', '12/01/2008', 8330], ['Citroen', 'C4 Coupe null', null, '8330'], ['Citroen', 'C4 Coupe empty', '', 8333], ['Audi', 'A4 Avant', '11/19/2011', '33900'], ['Opel', 'Astra', '02/02/2004', '7000'], ['BMW', '320i Coupe', '07/24/2011', 30500]],
  439. columns: [{}, {}, {}, {
  440. type: 'numeric'
  441. }],
  442. colHeaders: true,
  443. columnSorting: true
  444. });
  445. var htCore = getHtCore();
  446. this.sortByColumn(3);
  447. expect(hot.getDataAtCol(3)).toEqual(['6999.9999', '7000', 8330, '8330', 8333, 30500, '33900']);
  448. this.sortByColumn(3);
  449. expect(hot.getDataAtCol(3)).toEqual(['33900', 30500, 8333, 8330, '8330', '7000', '6999.9999']);
  450. this.sortByColumn(3);
  451. expect(hot.getDataAtCol(3)).toEqual(['6999.9999', 8330, '8330', 8333, '33900', '7000', 30500]);
  452. });
  453. it('numericSort comparing function shouldn\'t change order when comparing empty string, null and undefined', function () {
  454. var hot = handsontable({});
  455. var numericSort = hot.getPlugin('columnSorting').numericSort;
  456. expect(numericSort(false, {})(['key1', null], ['key2', null])).toEqual(0);
  457. expect(numericSort(false, {})(['key1', ''], ['key2', ''])).toEqual(0);
  458. expect(numericSort(false, {})(['key1', undefined], ['key2', undefined])).toEqual(0);
  459. expect(numericSort(false, {})(['key1', ''], ['key2', null])).toEqual(0);
  460. expect(numericSort(false, {})(['key1', null], ['key2', ''])).toEqual(0);
  461. expect(numericSort(false, {})(['key1', ''], ['key2', undefined])).toEqual(0);
  462. expect(numericSort(false, {})(['key1', undefined], ['key2', ''])).toEqual(0);
  463. expect(numericSort(false, {})(['key1', null], ['key2', undefined])).toEqual(0);
  464. expect(numericSort(false, {})(['key1', undefined], ['key2', null])).toEqual(0);
  465. });
  466. it('should sort table with multiple row headers', function () {
  467. var hot = handsontable({
  468. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  469. columns: [{}, {}, {
  470. type: 'date',
  471. dateFormat: 'mm/dd/yy'
  472. }, {
  473. type: 'numeric'
  474. }],
  475. colHeaders: true,
  476. columnSorting: true,
  477. removeRowPlugin: true // this plugin ads an extra row header, so now we have 2 instead of 1
  478. });
  479. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  480. this.sortByColumn(0); // sort by first column
  481. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  482. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('D');
  483. this.sortByColumn(1); // sort by second column
  484. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A');
  485. });
  486. it('should allow to define sorting column and order during initialization', function () {
  487. var hot = handsontable({
  488. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  489. colHeaders: true,
  490. columnSorting: {
  491. column: 0,
  492. sortOrder: true
  493. }
  494. });
  495. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  496. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('D');
  497. });
  498. it('should allow to change sorting column with updateSettings', function () {
  499. var hot = handsontable({
  500. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  501. colHeaders: true,
  502. columnSorting: {
  503. column: 0,
  504. sortOrder: true
  505. }
  506. });
  507. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  508. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('D');
  509. updateSettings({
  510. columnSorting: {
  511. column: 1,
  512. sortOrder: true
  513. }
  514. });
  515. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  516. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A');
  517. });
  518. it('should allow to change sorting order with updateSettings', function () {
  519. var hot = handsontable({
  520. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  521. colHeaders: true,
  522. columnSorting: {
  523. column: 0,
  524. sortOrder: true
  525. }
  526. });
  527. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  528. updateSettings({
  529. columnSorting: {
  530. column: 0,
  531. sortOrder: false
  532. }
  533. });
  534. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  535. });
  536. it('should allow to change if sorting empty cells with updateSettings', function () {
  537. var hot = handsontable({
  538. data: [[1, 'B'], [2, ''], [3, 'A'], [4, ''], [6, 'E'], [7, ''], [8, 'F']],
  539. colHeaders: true,
  540. columnSorting: {
  541. column: 1,
  542. sortOrder: false,
  543. sortEmptyCells: false
  544. }
  545. });
  546. updateSettings({
  547. columnSorting: {
  548. column: 1,
  549. sortOrder: true,
  550. sortEmptyCells: true
  551. }
  552. });
  553. // ASC with empty cells sorting
  554. expect(hot.getDataAtCol(0)).toEqual([2, 4, 7, 3, 1, 6, 8]);
  555. updateSettings({
  556. columnSorting: {
  557. column: 1,
  558. sortOrder: true,
  559. sortEmptyCells: false
  560. }
  561. });
  562. // ASC without empty cells sorting
  563. expect(hot.getDataAtCol(0)).toEqual([3, 1, 6, 8, 2, 4, 7]);
  564. });
  565. it('should NOT sort spare rows', function () {
  566. var myData = [{ a: 'aaa', b: 2, c: 3 }, { a: 'z', b: 11, c: -4 }, { a: 'dddd', b: 13, c: 13 }, { a: 'bbbb', b: 10, c: 11 }];
  567. function customIsEmptyRow(row) {
  568. var data = this.getSourceData();
  569. return data[row].isNew;
  570. }
  571. handsontable({
  572. data: myData,
  573. rowHeaders: true,
  574. colHeaders: ['A', 'B', 'C'],
  575. columns: [{ data: 'a', type: 'text' }, { data: 'b', type: 'text' }, { data: 'c', type: 'text' }],
  576. dataSchema: { isNew: true, a: false }, // default for a to avoid #bad value#
  577. columnSorting: true,
  578. minSpareRows: 3,
  579. isEmptyRow: customIsEmptyRow
  580. });
  581. // ASC
  582. updateSettings({
  583. columnSorting: {
  584. column: 0,
  585. sortOrder: true
  586. }
  587. });
  588. expect(getData()).toEqual([['aaa', 2, 3], ['bbbb', 10, 11], ['dddd', 13, 13], ['z', 11, -4], [false, null, null], [false, null, null], [false, null, null]]);
  589. updateSettings({
  590. columnSorting: {
  591. column: 0,
  592. sortOrder: false
  593. }
  594. });
  595. expect(getData()).toEqual([['z', 11, -4], ['dddd', 13, 13], ['bbbb', 10, 11], ['aaa', 2, 3], [false, null, null], [false, null, null], [false, null, null]]);
  596. });
  597. it('should reset column sorting with updateSettings', function () {
  598. var hot = handsontable({
  599. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  600. colHeaders: true,
  601. columnSorting: {
  602. column: 0,
  603. sortOrder: true
  604. }
  605. });
  606. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  607. updateSettings({
  608. columnSorting: void 0
  609. });
  610. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  611. });
  612. it('should expose sort method when columnSorting is enabled', function () {
  613. var hot = handsontable();
  614. expect(hot.getSettings().columnSorting).toBeFalsy();
  615. expect(hot.sort).toBeUndefined();
  616. updateSettings({
  617. columnSorting: true
  618. });
  619. expect(hot.getSettings().columnSorting).toBe(true);
  620. expect(hot.sort).toBeDefined();
  621. expect(_typeof(hot.sort)).toBe('function');
  622. updateSettings({
  623. columnSorting: false
  624. });
  625. expect(hot.getSettings().columnSorting).toBeFalsy();
  626. expect(hot.sort).toBeUndefined();
  627. });
  628. it('should sort table using HOT.sort method', function () {
  629. var hot = handsontable({
  630. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  631. columnSorting: true
  632. });
  633. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  634. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  635. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  636. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  637. hot.sort(0, true);
  638. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  639. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  640. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  641. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  642. });
  643. it('should reset column sorting with updateSettings', function () {
  644. var hot = handsontable({
  645. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  646. colHeaders: true,
  647. columnSorting: {
  648. column: 0,
  649. sortOrder: true
  650. }
  651. });
  652. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  653. updateSettings({
  654. columnSorting: void 0
  655. });
  656. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  657. });
  658. it('should fire beforeColumnSort event before sorting data', function () {
  659. var hot = handsontable({
  660. data: [[2], [4], [1], [3]],
  661. columnSorting: true
  662. });
  663. this.beforeColumnSortHandler = function () {
  664. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  665. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('4');
  666. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  667. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  668. };
  669. spyOn(this, 'beforeColumnSortHandler');
  670. hot.addHook('beforeColumnSort', this.beforeColumnSortHandler);
  671. var sortColumn = 0;
  672. var sortOrder = true;
  673. hot.sort(sortColumn, sortOrder);
  674. expect(this.beforeColumnSortHandler.calls.count()).toEqual(1);
  675. expect(this.beforeColumnSortHandler).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  676. });
  677. it('should not sorting column when beforeColumnSort returns false', function (done) {
  678. var hot = handsontable({
  679. data: [[2], [4], [1], [3]],
  680. columnSorting: true,
  681. beforeColumnSort: function beforeColumnSort() {
  682. return false;
  683. }
  684. });
  685. hot.sort(0, true);
  686. setTimeout(function () {
  687. expect(spec().$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('2');
  688. expect(spec().$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('4');
  689. expect(spec().$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('1');
  690. expect(spec().$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  691. done();
  692. }, 200);
  693. });
  694. it('should add beforeColumnSort event listener in constructor', function () {
  695. var beforeColumnSortCallback = jasmine.createSpy('beforeColumnSortHandler');
  696. var hot = handsontable({
  697. data: [[2], [4], [1], [3]],
  698. columnSorting: true,
  699. beforeColumnSort: beforeColumnSortCallback
  700. });
  701. var sortColumn = 0;
  702. var sortOrder = true;
  703. hot.sort(sortColumn, sortOrder);
  704. expect(beforeColumnSortCallback.calls.count()).toEqual(1);
  705. expect(beforeColumnSortCallback).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  706. });
  707. it('should fire afterColumnSort event before data has been sorted but before table render', function () {
  708. var hot = handsontable({
  709. data: [[2], [4], [1], [3]],
  710. columnSorting: true
  711. });
  712. var rendered = false;
  713. var afterColumnSortHandler = jasmine.createSpy('afterColumnSortHandler');
  714. var afterRenderSpy = jasmine.createSpy('afterRender');
  715. hot.addHook('afterColumnSort', function () {
  716. expect(rendered).toBe(false);
  717. afterColumnSortHandler.apply(afterColumnSortHandler, arguments);
  718. });
  719. hot.addHook('afterRender', function () {
  720. rendered = true;
  721. afterRenderSpy.apply(afterRenderSpy, arguments);
  722. });
  723. var sortColumn = 0;
  724. var sortOrder = true;
  725. afterRenderSpy.calls.reset();
  726. hot.sort(sortColumn, sortOrder);
  727. expect(afterColumnSortHandler.calls.count()).toBe(1);
  728. expect(afterColumnSortHandler).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  729. expect(afterRenderSpy.calls.count()).toBe(1);
  730. });
  731. it('should add afterColumnSort event listener in constructor', function () {
  732. var afterColumnSortCallback = jasmine.createSpy('afterColumnSortHandler');
  733. var hot = handsontable({
  734. data: [[2], [4], [1], [3]],
  735. columnSorting: true,
  736. afterColumnSort: afterColumnSortCallback
  737. });
  738. var sortColumn = 0;
  739. var sortOrder = true;
  740. hot.sort(sortColumn, sortOrder);
  741. expect(afterColumnSortCallback.calls.count()).toEqual(1);
  742. expect(afterColumnSortCallback).toHaveBeenCalledWith(sortColumn, sortOrder, void 0, void 0, void 0, void 0);
  743. });
  744. it('should insert row when plugin is enabled, but table hasn\'t been sorted', function () {
  745. var hot = handsontable({
  746. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  747. columnSorting: true
  748. });
  749. expect(countRows()).toEqual(4);
  750. expect(hot.sortColumn).toBeUndefined();
  751. alter('insert_row');
  752. expect(countRows()).toEqual(5);
  753. });
  754. it('should remove row when plugin is enabled, but table hasn\'t been sorted', function () {
  755. var hot = handsontable({
  756. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  757. columnSorting: true
  758. });
  759. expect(countRows()).toEqual(4);
  760. expect(hot.sortColumn).toBeUndefined();
  761. alter('remove_row');
  762. expect(countRows()).toEqual(3);
  763. });
  764. it('should display new row added directly to dataSource, when observeChanges plugin is enabled', function (done) {
  765. var data = [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']];
  766. var hot = handsontable({
  767. data: data,
  768. colHeaders: true,
  769. columnSorting: true,
  770. observeChanges: true
  771. });
  772. var htCore = getHtCore();
  773. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  774. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  775. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  776. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  777. this.sortByColumn(0);
  778. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  779. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  780. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  781. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  782. expect(htCore.find('tbody tr').length).toEqual(4);
  783. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  784. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  785. data.push([5, 'E']);
  786. setTimeout(function () {
  787. expect(countRows()).toEqual(5);
  788. expect(spec().$container.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('5');
  789. expect(spec().$container.find('tbody tr:eq(4) td:eq(1)').text()).toEqual('E');
  790. done();
  791. }, 200);
  792. });
  793. it('should not display new row added directly to dataSource, when observeChanges plugin is explicitly disabled', function (done) {
  794. var data = [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']];
  795. var hot = handsontable({
  796. data: data,
  797. colHeaders: true,
  798. columnSorting: true,
  799. observeChanges: false
  800. });
  801. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  802. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  803. var htCore = getHtCore();
  804. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  805. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  806. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  807. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  808. this.sortByColumn(0);
  809. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  810. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  811. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  812. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  813. expect(htCore.find('tbody tr').length).toEqual(4);
  814. data.push([5, 'E']);
  815. setTimeout(function () {
  816. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  817. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  818. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  819. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  820. expect(htCore.find('tbody tr').length).toEqual(4);
  821. expect(afterChangesObservedCallback).not.toHaveBeenCalled();
  822. done();
  823. }, 100);
  824. });
  825. it('should display new row added directly to dataSource, when observeChanges plugin status is undefined', function (done) {
  826. var data = [[1, 'B'], [0, 'A'], [3, 'D'], [2, 'C']];
  827. var onUpdateSettings = jasmine.createSpy('onUpdateSettings');
  828. var hot = handsontable({
  829. data: data,
  830. colHeaders: true,
  831. columnSorting: true,
  832. afterUpdateSettings: onUpdateSettings
  833. });
  834. var afterChangesObservedCallback = jasmine.createSpy('afterChangesObservedCallback');
  835. hot.addHook('afterChangesObserved', afterChangesObservedCallback);
  836. var htCore = getHtCore();
  837. // columnSorting enables observeChanges plugin by asynchronously invoking updateSettings
  838. setTimeout(function () {
  839. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  840. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  841. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  842. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  843. spec().sortByColumn(0);
  844. expect(htCore.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  845. expect(htCore.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  846. expect(htCore.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  847. expect(htCore.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  848. expect(htCore.find('tbody tr').length).toEqual(4);
  849. data.push([5, 'E']);
  850. }, 100);
  851. setTimeout(function () {
  852. expect(countRows()).toEqual(5);
  853. expect(htCore.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('5');
  854. expect(htCore.find('tbody tr:eq(4) td:eq(1)').text()).toEqual('E');
  855. done();
  856. }, 2000); // 2s delayed needs for safari env
  857. });
  858. it('should apply sorting when there are two tables and only one has sorting enabled and has been already sorted (#1020)', function () {
  859. var hot = handsontable({
  860. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  861. columnSorting: {
  862. column: 1
  863. }
  864. });
  865. this.$container2 = $('<div id="' + id + '-2"></div>').appendTo('body');
  866. this.$container2.handsontable();
  867. var hot2 = this.$container2.handsontable('getInstance');
  868. selectCell(0, 1);
  869. keyDown('enter');
  870. expect($('.handsontableInput').val()).toEqual('A');
  871. this.$container2.handsontable('destroy');
  872. this.$container2.remove();
  873. });
  874. it('should reset sorting after loading new data', function () {
  875. var hot = handsontable({
  876. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  877. columnSorting: true
  878. });
  879. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('1');
  880. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('0');
  881. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('3');
  882. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('2');
  883. hot.sort(0, true);
  884. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  885. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  886. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  887. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  888. loadData([[50, 'E'], [10, 'G'], [30, 'F'], [60, 'I'], [40, 'J'], [20, 'H']]);
  889. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('50');
  890. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('10');
  891. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('30');
  892. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('60');
  893. expect(this.$container.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('40');
  894. expect(this.$container.find('tbody tr:eq(5) td:eq(0)').text()).toEqual('20');
  895. });
  896. it('should reset sorting after loading new data (default sorting column and order set)', function () {
  897. var hot = handsontable({
  898. data: [[1, 'B'], [0, 'D'], [3, 'A'], [2, 'C']],
  899. columnSorting: {
  900. column: 1,
  901. sortOrder: true
  902. }
  903. });
  904. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('3');
  905. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  906. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  907. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('0');
  908. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('A');
  909. expect(this.$container.find('tbody tr:eq(1) td:eq(1)').text()).toEqual('B');
  910. expect(this.$container.find('tbody tr:eq(2) td:eq(1)').text()).toEqual('C');
  911. expect(this.$container.find('tbody tr:eq(3) td:eq(1)').text()).toEqual('D');
  912. hot.sort(0, true);
  913. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('0');
  914. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('1');
  915. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('2');
  916. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('3');
  917. loadData([[50, 'E'], [10, 'G'], [30, 'F'], [60, 'I'], [40, 'J'], [20, 'H']]);
  918. expect(this.$container.find('tbody tr:eq(0) td:eq(0)').text()).toEqual('50');
  919. expect(this.$container.find('tbody tr:eq(1) td:eq(0)').text()).toEqual('30');
  920. expect(this.$container.find('tbody tr:eq(2) td:eq(0)').text()).toEqual('10');
  921. expect(this.$container.find('tbody tr:eq(3) td:eq(0)').text()).toEqual('20');
  922. expect(this.$container.find('tbody tr:eq(4) td:eq(0)').text()).toEqual('60');
  923. expect(this.$container.find('tbody tr:eq(5) td:eq(0)').text()).toEqual('40');
  924. expect(this.$container.find('tbody tr:eq(0) td:eq(1)').text()).toEqual('E');
  925. expect(this.$container.find('tbody tr:eq(1) td:eq(1)').text()).toEqual('F');
  926. expect(this.$container.find('tbody tr:eq(2) td:eq(1)').text()).toEqual('G');
  927. expect(this.$container.find('tbody tr:eq(3) td:eq(1)').text()).toEqual('H');
  928. expect(this.$container.find('tbody tr:eq(4) td:eq(1)').text()).toEqual('I');
  929. expect(this.$container.find('tbody tr:eq(5) td:eq(1)').text()).toEqual('J');
  930. });
  931. it('should return updated data at specyfied row after sorted', function () {
  932. var hot = handsontable({
  933. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  934. colHeaders: true,
  935. rowHeaders: true,
  936. columnSorting: true
  937. });
  938. this.sortByColumn(0);
  939. expect(getDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  940. expect(getDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  941. this.sortByColumn(0);
  942. expect(getDataAtRow(0)).toEqual([5, 'Jane', 'Neat']);
  943. expect(getDataAtRow(4)).toEqual([1, 'Ted', 'Right']);
  944. this.sortByColumn(0);
  945. expect(getDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  946. expect(getDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  947. });
  948. it('should return updated data at specyfied col after sorted', function () {
  949. var hot = handsontable({
  950. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  951. colHeaders: true,
  952. rowHeaders: true,
  953. columnSorting: true
  954. });
  955. this.sortByColumn(0);
  956. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  957. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  958. this.sortByColumn(0);
  959. expect(getDataAtCol(0)).toEqual([5, 4, 3, 2, 1]);
  960. expect(getDataAtCol(1)).toEqual(['Jane', 'Sid', 'Joan', 'Frank', 'Ted']);
  961. this.sortByColumn(0);
  962. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  963. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  964. });
  965. it('should return original data source at specified row after sorted', function () {
  966. var hot = handsontable({
  967. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  968. colHeaders: true,
  969. rowHeaders: true,
  970. columnSorting: true
  971. });
  972. this.sortByColumn(0);
  973. expect(getDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  974. expect(getDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  975. expect(getSourceDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  976. expect(getSourceDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  977. this.sortByColumn(0);
  978. expect(getDataAtRow(0)).toEqual([5, 'Jane', 'Neat']);
  979. expect(getDataAtRow(4)).toEqual([1, 'Ted', 'Right']);
  980. expect(getSourceDataAtRow(0)).toEqual([1, 'Ted', 'Right']);
  981. expect(getSourceDataAtRow(4)).toEqual([5, 'Jane', 'Neat']);
  982. });
  983. it('should return original data source at specified col after sorted', function () {
  984. var hot = handsontable({
  985. data: [[1, 'Ted', 'Right'], [2, 'Frank', 'Honest'], [3, 'Joan', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  986. colHeaders: true,
  987. rowHeaders: true,
  988. columnSorting: true
  989. });
  990. this.sortByColumn(0);
  991. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  992. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  993. expect(getSourceDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  994. expect(getSourceDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  995. this.sortByColumn(0);
  996. expect(getDataAtCol(0)).toEqual([5, 4, 3, 2, 1]);
  997. expect(getDataAtCol(1)).toEqual(['Jane', 'Sid', 'Joan', 'Frank', 'Ted']);
  998. expect(getSourceDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  999. expect(getSourceDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  1000. this.sortByColumn(0);
  1001. expect(getDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  1002. expect(getDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  1003. expect(getSourceDataAtCol(0)).toEqual([1, 2, 3, 4, 5]);
  1004. expect(getSourceDataAtCol(1)).toEqual(['Ted', 'Frank', 'Joan', 'Sid', 'Jane']);
  1005. });
  1006. it('should ignore case when sorting', function () {
  1007. var hot = handsontable({
  1008. data: [[1, 'albuquerque'], [2, 'Alabama'], [3, 'Missouri']],
  1009. colHeaders: true,
  1010. columnSorting: true
  1011. });
  1012. this.sortByColumn(1);
  1013. expect(getDataAtCol(0)).toEqual([2, 1, 3]);
  1014. expect(getDataAtCol(1)).toEqual(['Alabama', 'albuquerque', 'Missouri']);
  1015. this.sortByColumn(1);
  1016. expect(getDataAtCol(0)).toEqual([3, 1, 2]);
  1017. expect(getDataAtCol(1)).toEqual(['Missouri', 'albuquerque', 'Alabama']);
  1018. });
  1019. it('should push empty cells to the end of sorted column', function () {
  1020. var hot = handsontable({
  1021. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  1022. colHeaders: true,
  1023. rowHeaders: true,
  1024. columnSorting: true,
  1025. minSpareRows: 1
  1026. });
  1027. this.sortByColumn(1);
  1028. expect(getDataAtCol(0)).toEqual([5, 4, 1, 2, 3, null]);
  1029. expect(getDataAtCol(1)).toEqual(['Jane', 'Sid', 'Ted', '', '', null]);
  1030. this.sortByColumn(1);
  1031. expect(getDataAtCol(0)).toEqual([1, 4, 5, 2, 3, null]);
  1032. expect(getDataAtCol(1)).toEqual(['Ted', 'Sid', 'Jane', '', '', null]);
  1033. });
  1034. it('should push numeric values before non-numeric values, when sorting ascending using the default sorting function', function () {
  1035. var hot = handsontable({
  1036. data: [[1, 'Ted', 123], [2, '', 'Some'], [3, '', 321], [4, 'Sid', 'String'], [5, 'Jane', 46]],
  1037. colHeaders: true,
  1038. columnSorting: true
  1039. });
  1040. this.sortByColumn(2);
  1041. expect(getDataAtCol(2)).toEqual([46, 123, 321, 'Some', 'String']);
  1042. this.sortByColumn(2);
  1043. expect(getDataAtCol(2)).toEqual(['String', 'Some', 321, 123, 46]);
  1044. });
  1045. it('should add a sorting indicator to the column header after it\'s been sorted, only if sortIndicator property is set to true', function () {
  1046. var hot = handsontable({
  1047. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  1048. colHeaders: true,
  1049. columnSorting: true
  1050. });
  1051. this.sortByColumn(1);
  1052. var sortedColumn = this.$container.find('th span.columnSorting')[1],
  1053. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1054. expect(afterValue === '' || afterValue === 'none').toBe(true);
  1055. // ---------------------------------
  1056. // INDICATOR SET FOR THE WHOLE TABLE
  1057. // ---------------------------------
  1058. hot.updateSettings({
  1059. sortIndicator: true
  1060. });
  1061. this.sortByColumn(1);
  1062. // descending (updateSettings doesn't reset sorting stack)
  1063. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1064. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1065. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  1066. this.sortByColumn(1);
  1067. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1068. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1069. expect(afterValue === '' || afterValue === 'none').toBe(true);
  1070. this.sortByColumn(1);
  1071. // ascending
  1072. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1073. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1074. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1075. // ---------------------------------
  1076. // INDICATOR SET FOR A SINGLE COLUMN
  1077. // ---------------------------------
  1078. hot.updateSettings({
  1079. sortIndicator: void 0,
  1080. columns: [{}, {}, { sortIndicator: true }]
  1081. });
  1082. this.sortByColumn(0);
  1083. sortedColumn = this.$container.find('th span.columnSorting')[0];
  1084. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1085. expect(afterValue === '' || afterValue === 'none').toBe(true);
  1086. this.sortByColumn(1);
  1087. // descending
  1088. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1089. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1090. expect(afterValue === '' || afterValue === 'none').toBe(true);
  1091. this.sortByColumn(2);
  1092. sortedColumn = this.$container.find('th span.columnSorting')[2];
  1093. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1094. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1095. });
  1096. it('should change sorting indicator state on every `hot.sort()` method call (continuously for the same column)', function () {
  1097. var hot = handsontable({
  1098. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  1099. colHeaders: true,
  1100. columnSorting: true,
  1101. sortIndicator: true
  1102. });
  1103. hot.sort(1);
  1104. // ascending
  1105. var sortedColumn = this.$container.find('th span.columnSorting')[1];
  1106. var afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1107. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1108. hot.sort(1);
  1109. // descending
  1110. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1111. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1112. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  1113. hot.sort(1);
  1114. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1115. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1116. expect(afterValue === '' || afterValue === 'none').toBe(true);
  1117. hot.sort(1);
  1118. // ascending
  1119. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1120. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1121. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1122. hot.sort(1);
  1123. // descending
  1124. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1125. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1126. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  1127. });
  1128. it('should change sorting indicator state on every `hot.sort()` method (calling for different columns)', function () {
  1129. var hot = handsontable({
  1130. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  1131. colHeaders: true,
  1132. columnSorting: true,
  1133. sortIndicator: true
  1134. });
  1135. hot.sort(1);
  1136. // ascending
  1137. var sortedColumn = this.$container.find('th span.columnSorting')[1];
  1138. var afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1139. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1140. hot.sort(2);
  1141. // ascending
  1142. sortedColumn = this.$container.find('th span.columnSorting')[2];
  1143. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1144. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1145. hot.sort(1);
  1146. // ascending
  1147. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1148. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1149. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1150. hot.sort(2, false);
  1151. // descending
  1152. sortedColumn = this.$container.find('th span.columnSorting')[2];
  1153. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1154. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  1155. hot.sort(2, false);
  1156. // descending
  1157. sortedColumn = this.$container.find('th span.columnSorting')[2];
  1158. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1159. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  1160. hot.sort(2, true);
  1161. // ascending
  1162. sortedColumn = this.$container.find('th span.columnSorting')[2];
  1163. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1164. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1165. });
  1166. it('should change sorting indicator state when initial column sorting was provided', function () {
  1167. var hot = handsontable({
  1168. data: [[1, 'Ted', 'Right'], [2, '', 'Honest'], [3, '', 'Well'], [4, 'Sid', 'Strong'], [5, 'Jane', 'Neat']],
  1169. colHeaders: true,
  1170. columnSorting: {
  1171. column: 1,
  1172. sortOrder: false
  1173. },
  1174. sortIndicator: true
  1175. });
  1176. // descending
  1177. var sortedColumn = this.$container.find('th span.columnSorting')[1];
  1178. var afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1179. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  1180. hot.sort(1);
  1181. // default
  1182. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1183. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1184. expect(afterValue === '' || afterValue === 'none').toBe(true);
  1185. hot.sort(1);
  1186. // ascending
  1187. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1188. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1189. expect(afterValue.indexOf(String.fromCharCode(9650))).toBeGreaterThan(-1);
  1190. hot.sort(1);
  1191. // descending
  1192. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1193. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1194. expect(afterValue.indexOf(String.fromCharCode(9660))).toBeGreaterThan(-1);
  1195. hot.sort(1);
  1196. // default
  1197. sortedColumn = this.$container.find('th span.columnSorting')[1];
  1198. afterValue = window.getComputedStyle(sortedColumn, ':after').getPropertyValue('content');
  1199. expect(afterValue === '' || afterValue === 'none').toBe(true);
  1200. });
  1201. it('should properly sort the table, when it\'s scrolled to the far right', function () {
  1202. var data = [['Jasmine Ferguson', 'Britney Carey', 'Kelly Decker', 'Lacey Mcleod', 'Leona Shaffer', 'Kelli Ochoa', 'Adele Roberson', 'Viola Snow', 'Barron Cherry', 'Calhoun Lane', 'Elvia Andrews', 'Katheryn Dale', 'Dorthy Hale', 'Munoz Randall', 'Fields Morse', 'Hubbard Nichols', 'Chang Yang', 'Osborn Anthony', 'Owens Warner', 'Gloria Hampton'], ['Lane Hill', 'Belinda Mathews', 'York Gray', 'Celina Stone', 'Victoria Mays', 'Angelina Lott', 'Joyce Mason', 'Shawn Rodriguez', 'Susanna Mayo', 'Wolf Fuller', 'Long Hester', 'Dudley Doyle', 'Wilder Sutton', 'Oneal Avery', 'James Mclaughlin', 'Lenora Guzman', 'Mcmahon Sullivan', 'Abby Weeks', 'Beverly Joseph', 'Rosalind Church'], ['Myrtle Landry', 'Hays Huff', 'Hernandez Benjamin', 'Mclaughlin Garza', 'Franklin Barton', 'Lara Buchanan', 'Ratliff Beck', 'Rosario Munoz', 'Isabelle Dalton', 'Smith Woodard', 'Marjorie Marshall', 'Spears Stein', 'Brianna Bowman', 'Marci Clay', 'Palmer Harrell', 'Ball Levy', 'Shelley Mendoza', 'Morrow Glass', 'Baker Knox', 'Adrian Holman'], ['Trisha Howell', 'Brooke Harrison', 'Anthony Watkins', 'Ellis Cobb', 'Sheppard Dillon', 'Mathis Bray', 'Foreman Burns', 'Lina Glenn', 'Giles Pollard', 'Weiss Ballard', 'Lynnette Smith', 'Flores Kline', 'Graciela Singleton', 'Santiago Mcclure', 'Claudette Battle', 'Nita Holloway', 'Eula Wolfe', 'Pruitt Stokes', 'Felicia Briggs', 'Melba Bradshaw']];
  1203. var hot = handsontable({
  1204. data: data,
  1205. colHeaders: true,
  1206. columnSorting: true
  1207. });
  1208. hot.view.wt.wtOverlays.leftOverlay.scrollTo(15);
  1209. hot.render();
  1210. hot.sort(15);
  1211. expect(getDataAtCell(0, 15)).toEqual('Ball Levy');
  1212. expect(getDataAtCell(1, 15)).toEqual('Hubbard Nichols');
  1213. expect(getDataAtCell(2, 15)).toEqual('Lenora Guzman');
  1214. expect(getDataAtCell(3, 15)).toEqual('Nita Holloway');
  1215. hot.sort(15);
  1216. expect(getDataAtCell(3, 15)).toEqual('Ball Levy');
  1217. expect(getDataAtCell(2, 15)).toEqual('Hubbard Nichols');
  1218. expect(getDataAtCell(1, 15)).toEqual('Lenora Guzman');
  1219. expect(getDataAtCell(0, 15)).toEqual('Nita Holloway');
  1220. hot.sort(15);
  1221. expect(getDataAtCell(0, 15)).toEqual('Hubbard Nichols');
  1222. expect(getDataAtCell(1, 15)).toEqual('Lenora Guzman');
  1223. expect(getDataAtCell(2, 15)).toEqual('Ball Levy');
  1224. expect(getDataAtCell(3, 15)).toEqual('Nita Holloway');
  1225. });
  1226. it('should allow specifiyng a custom sorting function', function () {
  1227. var data = [['1 inch'], ['1 yard'], ['2 feet'], ['0.2 miles']];
  1228. var hot = handsontable({
  1229. data: data,
  1230. colHeaders: true,
  1231. columnSorting: true,
  1232. columns: [{
  1233. sortFunction: function sortFunction(sortOrder) {
  1234. return function (a, b) {
  1235. var unitsRatios = {
  1236. inch: 1,
  1237. yard: 36,
  1238. feet: 12,
  1239. miles: 63360
  1240. };
  1241. var newA = a[1],
  1242. newB = b[1];
  1243. Handsontable.helper.objectEach(unitsRatios, function (val, prop) {
  1244. if (a[1].indexOf(prop) > -1) {
  1245. newA = parseFloat(a[1].replace(prop, '')) * val;
  1246. return false;
  1247. }
  1248. });
  1249. Handsontable.helper.objectEach(unitsRatios, function (val, prop) {
  1250. if (b[1].indexOf(prop) > -1) {
  1251. newB = parseFloat(b[1].replace(prop, '')) * val;
  1252. return false;
  1253. }
  1254. });
  1255. if (newA < newB) {
  1256. return sortOrder ? -1 : 1;
  1257. }
  1258. if (newA > newB) {
  1259. return sortOrder ? 1 : -1;
  1260. }
  1261. return 0;
  1262. };
  1263. }
  1264. }]
  1265. });
  1266. expect(getDataAtCell(0, 0)).toEqual('1 inch');
  1267. expect(getDataAtCell(1, 0)).toEqual('1 yard');
  1268. expect(getDataAtCell(2, 0)).toEqual('2 feet');
  1269. expect(getDataAtCell(3, 0)).toEqual('0.2 miles');
  1270. hot.sort(0);
  1271. expect(getDataAtCell(0, 0)).toEqual('1 inch');
  1272. expect(getDataAtCell(1, 0)).toEqual('2 feet');
  1273. expect(getDataAtCell(2, 0)).toEqual('1 yard');
  1274. expect(getDataAtCell(3, 0)).toEqual('0.2 miles');
  1275. hot.sort(0);
  1276. expect(getDataAtCell(0, 0)).toEqual('0.2 miles');
  1277. expect(getDataAtCell(1, 0)).toEqual('1 yard');
  1278. expect(getDataAtCell(2, 0)).toEqual('2 feet');
  1279. expect(getDataAtCell(3, 0)).toEqual('1 inch');
  1280. hot.sort(0);
  1281. expect(getDataAtCell(0, 0)).toEqual('1 inch');
  1282. expect(getDataAtCell(1, 0)).toEqual('1 yard');
  1283. expect(getDataAtCell(2, 0)).toEqual('2 feet');
  1284. expect(getDataAtCell(3, 0)).toEqual('0.2 miles');
  1285. });
  1286. it('should properly sort integers with nulls', function () {
  1287. var hot = handsontable({
  1288. data: [['12'], [null], ['10'], ['-5'], [null], ['1000']],
  1289. colHeaders: true,
  1290. columnSorting: true
  1291. });
  1292. this.sortByColumn(0);
  1293. expect(getDataAtCol(0)).toEqual(['-5', '10', '12', '1000', null, null]);
  1294. this.sortByColumn(0);
  1295. expect(getDataAtCol(0)).toEqual(['1000', '12', '10', '-5', null, null]);
  1296. });
  1297. it('should properly sort floating points', function () {
  1298. var hot = handsontable({
  1299. data: [['0.0561'], ['-10.67'], ['-4.1'], ['-0.01'], ['-127'], ['1000']],
  1300. colHeaders: true,
  1301. columnSorting: true
  1302. });
  1303. this.sortByColumn(0);
  1304. expect(getDataAtCol(0)).toEqual(['-127', '-10.67', '-4.1', '-0.01', '0.0561', '1000']);
  1305. this.sortByColumn(0);
  1306. expect(getDataAtCol(0)).toEqual(['1000', '0.0561', '-0.01', '-4.1', '-10.67', '-127']);
  1307. });
  1308. it('should properly sort floating points with nulls', function () {
  1309. var hot = handsontable({
  1310. data: [['0.0561'], ['-10.67'], [null], ['-4.1'], ['-0.01'], [null], ['-127'], ['1000'], [null]],
  1311. colHeaders: true,
  1312. columnSorting: true
  1313. });
  1314. this.sortByColumn(0);
  1315. expect(getDataAtCol(0)).toEqual(['-127', '-10.67', '-4.1', '-0.01', '0.0561', '1000', null, null, null]);
  1316. this.sortByColumn(0);
  1317. expect(getDataAtCol(0)).toEqual(['1000', '0.0561', '-0.01', '-4.1', '-10.67', '-127', null, null, null]);
  1318. });
  1319. it('should properly sort floating points with non-numerical values', function () {
  1320. var hot = handsontable({
  1321. data: [['0.0561'], ['-10.67'], ['a'], ['-4.1'], ['-0.01'], ['b'], ['-127'], ['1000'], ['hello']],
  1322. colHeaders: true,
  1323. columnSorting: true
  1324. });
  1325. this.sortByColumn(0);
  1326. expect(getDataAtCol(0)).toEqual(['-127', '-10.67', '-4.1', '-0.01', '0.0561', '1000', 'a', 'b', 'hello']);
  1327. this.sortByColumn(0);
  1328. expect(getDataAtCol(0)).toEqual(['hello', 'b', 'a', '1000', '0.0561', '-0.01', '-4.1', '-10.67', '-127']);
  1329. });
  1330. it('should modify row translating process when soring is applied (visual to physical and vice versa)', function () {
  1331. var hot = handsontable({
  1332. data: [[2], [4], [1], [3]],
  1333. colHeaders: true,
  1334. columnSorting: true
  1335. });
  1336. this.sortByColumn(0);
  1337. expect(hot.toPhysicalRow(0)).toBe(2);
  1338. expect(hot.toPhysicalRow(1)).toBe(0);
  1339. expect(hot.toPhysicalRow(2)).toBe(3);
  1340. expect(hot.toPhysicalRow(3)).toBe(1);
  1341. expect(hot.toVisualRow(0)).toBe(1);
  1342. expect(hot.toVisualRow(1)).toBe(3);
  1343. expect(hot.toVisualRow(2)).toBe(0);
  1344. expect(hot.toVisualRow(3)).toBe(2);
  1345. });
  1346. describe('should return sorted properly data when maxRows or / and minSpareRow options are set', function () {
  1347. var testSorting = function testSorting(desc, config, result) {
  1348. it(desc, function () {
  1349. handsontable({
  1350. data: Handsontable.helper.createSpreadsheetData(config.rows, config.columns),
  1351. maxRows: config.maxRow,
  1352. minSpareRows: config.minSpareRows,
  1353. columnSorting: {
  1354. column: config.sortByColumnIndex,
  1355. sortOrder: config.sortOrder
  1356. }
  1357. });
  1358. expect(getData().length).toEqual(result.dataLength);
  1359. for (var i = 0; i < result.expectations.length; i += 1) {
  1360. expect(getDataAtCell(result.expectations[i].rowIndex, result.expectations[i].columnIndex)).toEqual(result.expectations[i].value);
  1361. }
  1362. });
  1363. };
  1364. testSorting('maxRows < data.length', { rows: 9, columns: 9, maxRow: 6, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 6, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C6' }] });
  1365. testSorting('maxRows > data.length', { rows: 8, columns: 8, maxRow: 20, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 8, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C8' }] });
  1366. testSorting('minSpareRows is set; maxRows < data.length', { rows: 9, columns: 9, maxRow: 5, minSpareRows: 3, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 5, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C5' }] });
  1367. testSorting('minSpareRows is set; maxRows === data.length', { rows: 6, columns: 6, maxRow: 9, minSpareRows: 3, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 6 + 3, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C6' }] });
  1368. testSorting('minSpareRows is set; maxRows > data.length', { rows: 9, columns: 9, maxRow: 15, minSpareRows: 2, sortByColumnIndex: 1, sortOrder: false }, { dataLength: 9 + 2, expectations: [{ rowIndex: 0, columnIndex: 2, value: 'C9' }] });
  1369. });
  1370. });