dateEditor.spec.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. describe('DateEditor', () => {
  2. const id = 'testContainer';
  3. beforeEach(function() {
  4. this.$container = $(`<div id="${id}"></div>`).appendTo('body');
  5. });
  6. afterEach(function() {
  7. if (this.$container) {
  8. destroy();
  9. this.$container.remove();
  10. }
  11. });
  12. function getDates() {
  13. return [
  14. ['01/14/2006'],
  15. ['12/01/2008'],
  16. ['11/19/2011'],
  17. ['02/02/2004'],
  18. ['07/24/2011']
  19. ];
  20. }
  21. it('should display Pikday calendar', () => {
  22. handsontable({
  23. data: getDates(),
  24. columns: [
  25. {
  26. type: 'date'
  27. }
  28. ]
  29. });
  30. expect($('.pika-single').is(':visible')).toBe(false);
  31. selectCell(0, 0);
  32. keyDown('enter');
  33. expect($('.pika-single').is(':visible')).toBe(true);
  34. });
  35. it('should pass date picker config object to Pikday', () => {
  36. const onOpenSpy = jasmine.createSpy('open');
  37. const onCloseSpy = jasmine.createSpy('close');
  38. const hot = handsontable({
  39. data: getDates(),
  40. columns: [
  41. {
  42. type: 'date',
  43. datePickerConfig: {
  44. firstDay: 1,
  45. field: 'field', // read only - shouldn't overwrite
  46. trigger: 'trigger', // read only - shouldn't overwrite
  47. container: 'container', // read only - shouldn't overwrite
  48. bound: true, // read only - shouldn't overwrite
  49. i18n: {
  50. previousMonth: 'Poprzedni',
  51. nextMonth: 'Następny',
  52. months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
  53. weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
  54. weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
  55. },
  56. onOpen: onOpenSpy,
  57. onClose: onCloseSpy
  58. }
  59. }
  60. ]
  61. });
  62. selectCell(0, 0);
  63. keyDown('enter');
  64. keyDown('esc');
  65. const config = hot.getActiveEditor().$datePicker.config();
  66. expect(config.field instanceof HTMLElement).toBe(true);
  67. expect(config.trigger instanceof HTMLElement).toBe(true);
  68. expect(config.container instanceof HTMLElement).toBe(true);
  69. expect(config.bound).toBe(false);
  70. expect(config.firstDay).toBe(1);
  71. expect(config.i18n.previousMonth).toBe('Poprzedni');
  72. expect(config.i18n.nextMonth).toBe('Następny');
  73. expect(onOpenSpy).toHaveBeenCalled();
  74. expect(onCloseSpy).toHaveBeenCalled();
  75. });
  76. it('should remove any HTML connected with Pikaday Calendar', () => {
  77. handsontable({
  78. data: getDates(),
  79. columns: [
  80. {
  81. type: 'date'
  82. }
  83. ]
  84. });
  85. expect($('.pika-single').length).toBe(0);
  86. selectCell(0, 0);
  87. keyDown('enter');
  88. expect($('.pika-single').length).toBe(1);
  89. destroy();
  90. expect($('.pika-single').length).toBe(0);
  91. });
  92. it('should select date corresponding to cell value', () => {
  93. handsontable({
  94. data: getDates(),
  95. columns: [
  96. {
  97. type: 'date',
  98. dateFormat: 'MM/DD/YYYY'
  99. }
  100. ]
  101. });
  102. selectCell(0, 0);
  103. keyDown('enter');
  104. const date = new Date(getDates()[0][0]);
  105. expect($('.pika-single').find('.pika-select-year').find(':selected').val()).toMatch(date.getFullYear().toString());
  106. expect($('.pika-single').find('.pika-select-month').find(':selected').val()).toMatch(date.getMonth().toString());
  107. expect($('.pika-single').find('.pika-table .is-selected').text()).toMatch(date.getDate().toString());
  108. });
  109. it('should save new date after clicked on calendar', (done) => {
  110. handsontable({
  111. data: getDates(),
  112. columns: [
  113. {
  114. type: 'date',
  115. dateFormat: 'MM/DD/YYYY'
  116. }
  117. ]
  118. });
  119. selectCell(0, 0);
  120. expect(getDataAtCell(0, 0)).toMatch('01/14/2006');
  121. keyDown('enter');
  122. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(0) td:eq(0) button'));
  123. setTimeout(() => {
  124. expect(getDataAtCell(0, 0)).toMatch('01/01/2006');
  125. done();
  126. }, 150);
  127. });
  128. it('should display fill handle after selected date on calendar', (done) => {
  129. handsontable({
  130. data: getDates(),
  131. columns: [
  132. {
  133. type: 'date',
  134. dateFormat: 'MM/DD/YYYY'
  135. }
  136. ]
  137. });
  138. selectCell(0, 0);
  139. expect(getDataAtCell(0, 0)).toMatch('01/14/2006');
  140. keyDown('enter');
  141. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(0) td:eq(0) button'));
  142. setTimeout(() => {
  143. expect(getDataAtCell(0, 0)).toMatch('01/01/2006');
  144. expect($('.htBorders .current.corner').is(':visible')).toBe(true);
  145. done();
  146. }, 150);
  147. });
  148. it('should setup in settings and display defaultDate on calendar', (done) => {
  149. handsontable({
  150. data: getDates(),
  151. minSpareRows: 1,
  152. columns: [
  153. {
  154. type: 'date',
  155. dateFormat: 'MM/DD/YYYY',
  156. defaultDate: '01/01/1900'
  157. }
  158. ]
  159. });
  160. selectCell(5, 0);
  161. expect(getDataAtCell(5, 0)).toBe(null);
  162. keyDown('enter');
  163. const date = new Date('01/01/1900');
  164. expect($('.pika-single').find('.pika-select-year').find(':selected').val()).toMatch(date.getFullYear().toString());
  165. expect($('.pika-single').find('.pika-select-month').find(':selected').val()).toMatch(date.getMonth().toString());
  166. expect($('.pika-single').find('.pika-table .is-selected').text()).toMatch(date.getDate().toString());
  167. keyDown('enter');
  168. setTimeout(() => {
  169. expect(getDataAtCell(5, 0)).toMatch('01/01/1900');
  170. done();
  171. }, 150);
  172. });
  173. it('should close calendar after picking new date', () => {
  174. handsontable({
  175. data: getDates(),
  176. columns: [
  177. {
  178. type: 'date',
  179. dateFormat: 'MM/DD/YYYY'
  180. }
  181. ]
  182. });
  183. selectCell(0, 0);
  184. keyDown('enter');
  185. expect($('.pika-single').is(':visible')).toBe(true);
  186. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(0) td:eq(0) button'));
  187. expect($('.pika-single').is(':visible')).toBe(false);
  188. });
  189. it('should enable to input any value in textarea', async() => {
  190. const hot = handsontable({
  191. data: getDates(),
  192. columns: [
  193. {
  194. type: 'date'
  195. }
  196. ]
  197. });
  198. selectCell(0, 0);
  199. const editor = hot.getActiveEditor();
  200. editor.beginEditing();
  201. expect(editor.isOpened()).toBe(true);
  202. editor.TEXTAREA.value = 'foo';
  203. keyDownUp('o'.charCodeAt(0));
  204. expect(editor.getValue()).toEqual('foo');
  205. editor.finishEditing();
  206. await sleep(30);
  207. expect(getDataAtCell(0, 0)).toEqual('foo');
  208. });
  209. it('should not close editor when inserting wrong value and allowInvalid is set to false, (#5419)', async() => {
  210. const hot = handsontable({
  211. data: getDates(),
  212. allowInvalid: false,
  213. columns: [
  214. {
  215. type: 'date'
  216. }
  217. ]
  218. });
  219. selectCell(0, 0);
  220. const editor = hot.getActiveEditor();
  221. editor.beginEditing();
  222. expect(editor.isOpened()).toBe(true);
  223. editor.TEXTAREA.value = 'foo';
  224. expect(editor.getValue()).toEqual('foo');
  225. editor.finishEditing();
  226. await sleep(30);
  227. expect(editor.isOpened()).toBe(true);
  228. expect(editor.getValue()).toEqual('foo');
  229. });
  230. // Input element can not lose the focus while entering new characters. It breaks IME editor functionality for Asian users.
  231. it('should not lose the focus on input element while inserting new characters (#839)', async() => {
  232. let blured = false;
  233. const listener = () => {
  234. blured = true;
  235. };
  236. const hot = handsontable({
  237. data: [
  238. ['one', 'two'],
  239. ['three', 'four']
  240. ],
  241. columns: [
  242. {
  243. type: 'date',
  244. },
  245. {},
  246. ],
  247. });
  248. selectCell(0, 0);
  249. keyDownUp('enter');
  250. hot.getActiveEditor().TEXTAREA.addEventListener('blur', listener);
  251. await sleep(200);
  252. hot.getActiveEditor().TEXTAREA.value = 't';
  253. keyDownUp('t'.charCodeAt(0));
  254. hot.getActiveEditor().TEXTAREA.value = 'te';
  255. keyDownUp('e'.charCodeAt(0));
  256. hot.getActiveEditor().TEXTAREA.value = 'teo';
  257. keyDownUp('o'.charCodeAt(0));
  258. expect(blured).toBeFalsy();
  259. hot.getActiveEditor().TEXTAREA.removeEventListener('blur', listener);
  260. });
  261. it('should restore original when edited and pressed ESC ', async() => {
  262. const hot = handsontable({
  263. data: getDates(),
  264. columns: [
  265. {
  266. type: 'date'
  267. }
  268. ]
  269. });
  270. selectCell(0, 0);
  271. const editor = hot.getActiveEditor();
  272. editor.beginEditing();
  273. expect(editor.isOpened()).toBe(true);
  274. editor.TEXTAREA.value = 'foo';
  275. expect(editor.getValue()).toEqual('foo');
  276. keyDownUp(Handsontable.helper.KEY_CODES.ESCAPE); // cancel editing
  277. await sleep(30);
  278. editor.finishEditing();
  279. expect(getDataAtCell(0, 0)).toEqual('01/14/2006');
  280. });
  281. it('should display a calendar based on a current date, even if a date in a wrong format was entered previously', (done) => {
  282. handsontable({
  283. data: Handsontable.helper.createSpreadsheetData(5, 2),
  284. columns: [
  285. { type: 'date' },
  286. { type: 'date', dateFormat: 'YYYY-MM-DD' }
  287. ],
  288. minSpareRows: 1
  289. });
  290. setDataAtCell(4, 1, '15-11-11');
  291. setTimeout(() => {
  292. selectCell(5, 1);
  293. keyDown('enter');
  294. expect($('.pika-single').is(':visible')).toBe(true);
  295. mouseDown($('.pika-single').find('.pika-table tbody tr:eq(3) td:eq(3) button'));
  296. }, 150);
  297. setTimeout(() => {
  298. const resultDate = getDataAtCell(5, 1);
  299. expect(moment(resultDate).year()).toEqual(moment().year());
  300. expect(moment(resultDate).month()).toEqual(moment().month());
  301. done();
  302. }, 300);
  303. });
  304. it('should display Pikaday Calendar bottom of the selected cell', () => {
  305. const hot = handsontable({
  306. data: Handsontable.helper.createSpreadsheetData(5, 2),
  307. columns: [
  308. { type: 'date' },
  309. { type: 'date' }
  310. ]
  311. });
  312. selectCell(1, 1);
  313. keyDown('enter');
  314. const cellOffset = $(hot.getActiveEditor().TD).offset();
  315. const datePickerOffset = $('.pika-single').offset();
  316. // 23 is a height of the editor cell
  317. expect(cellOffset.top + 23).toBeCloseTo(datePickerOffset.top, 0);
  318. expect(cellOffset.left).toBeCloseTo(datePickerOffset.left, 0);
  319. });
  320. it('should display Pikaday Calendar bottom of the selected cell when table have scrolls', () => {
  321. const container = $('#testContainer');
  322. container[0].style.height = '300px';
  323. container[0].style.width = '200px';
  324. container[0].style.overflow = 'hidden';
  325. const hot = handsontable({
  326. data: Handsontable.helper.createSpreadsheetData(30, 10),
  327. colWidths: 60,
  328. columns: [
  329. { type: 'date' },
  330. { type: 'date' },
  331. { type: 'date' },
  332. { type: 'date' },
  333. { type: 'date' },
  334. { type: 'date' },
  335. { type: 'date' }
  336. ]
  337. });
  338. selectCell(20, 6);
  339. keyDown('enter');
  340. const cellOffset = $(hot.getActiveEditor().TD).offset();
  341. const datePickerOffset = $('.pika-single').offset();
  342. expect(cellOffset.top + 23).toBeCloseTo(datePickerOffset.top, 0);
  343. expect(cellOffset.left).toBeCloseTo(datePickerOffset.left, 0);
  344. });
  345. it('should not modify the edited date and time, when opening the editor', () => {
  346. const hot = handsontable({
  347. data: [['02/02/2015 8:00 AM']],
  348. columns: [
  349. {
  350. type: 'date',
  351. dateFormat: 'MM/DD/YYYY h:mm A',
  352. correctFormat: true,
  353. defaultDate: '01/01/1900',
  354. allowEmpty: false,
  355. }
  356. ]
  357. });
  358. // setDataAtCell(0, 0, '02/02/2015 8:00 AM');
  359. const cellValue = getDataAtCell(0, 0);
  360. selectCell(0, 0);
  361. keyDown('enter');
  362. const editor = hot.getActiveEditor();
  363. expect(editor.TEXTAREA.value).toEqual(cellValue);
  364. });
  365. describe('IME support', () => {
  366. it('should focus editable element after selecting the cell', async() => {
  367. handsontable({
  368. columns: [
  369. {
  370. editor: 'date',
  371. }
  372. ]
  373. });
  374. selectCell(0, 0, 0, 0, true, false);
  375. await sleep(10);
  376. expect(document.activeElement).toBe(getActiveEditor().TEXTAREA);
  377. });
  378. });
  379. });