b6a4459a94c4c0632ca7dfb9f6d2a7b870cc08ef44f942fcec0e9fb31fa94b5000551729a986995e895665530b2d3625ad996009bbd89ce0ae1873187f9b84 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import {getProperty} from './helpers/object';
  2. import {arrayEach} from './helpers/array';
  3. import {rangeEach} from './helpers/number';
  4. /**
  5. * @class DataSource
  6. * @private
  7. */
  8. class DataSource {
  9. constructor(hotInstance, dataSource = []) {
  10. /**
  11. * Instance of Handsontable.
  12. *
  13. * @type {Handsontable}
  14. */
  15. this.hot = hotInstance;
  16. /**
  17. * Data source
  18. *
  19. * @type {Array}
  20. */
  21. this.data = dataSource;
  22. /**
  23. * Type of data source.
  24. *
  25. * @type {String}
  26. * @default 'array'
  27. */
  28. this.dataType = 'array';
  29. this.colToProp = () => {};
  30. this.propToCol = () => {};
  31. }
  32. /**
  33. * Get all data.
  34. *
  35. * @param {Boolean} [toArray=false] If `true` return source data as an array of arrays even when source data was provided
  36. * in another format.
  37. * @returns {Array}
  38. */
  39. getData(toArray = false) {
  40. let result = this.data;
  41. if (toArray) {
  42. result = this.getByRange(
  43. {row: 0, col: 0},
  44. {row: Math.max(this.countRows() - 1, 0), col: Math.max(this.countColumns() - 1, 0)},
  45. true
  46. );
  47. }
  48. return result;
  49. }
  50. /**
  51. * Set new data source.
  52. *
  53. * @param data {Array}
  54. */
  55. setData(data) {
  56. this.data = data;
  57. }
  58. /**
  59. * Returns array of column values from the data source. `column` is the index of the row in the data source.
  60. *
  61. * @param {Number} column
  62. * @returns {Array}
  63. */
  64. getAtColumn(column) {
  65. let result = [];
  66. arrayEach(this.data, (row) => {
  67. let property = this.colToProp(column);
  68. if (typeof property === 'string') {
  69. row = getProperty(row, property);
  70. } else {
  71. row = row[property];
  72. }
  73. result.push(row);
  74. });
  75. return result;
  76. }
  77. /**
  78. * Returns a single row of the data (array or object, depending on what you have). `row` is the index of the row in the data source.
  79. *
  80. * @param {Number} row
  81. * @returns {Array|Object}
  82. */
  83. getAtRow(row) {
  84. return this.data[row];
  85. }
  86. /**
  87. * Returns a single value from the data.
  88. *
  89. * @param {Number} row Row index.
  90. * @param {Number} column Column index.
  91. * @returns {*}
  92. */
  93. getAtCell(row, column) {
  94. let result = null;
  95. let modifyRowData = this.hot.runHooks('modifyRowData', row);
  96. let dataRow = isNaN(modifyRowData) ? modifyRowData : this.data[row];
  97. if (dataRow) {
  98. let prop = this.colToProp(column);
  99. if (typeof prop === 'string') {
  100. result = getProperty(dataRow, prop);
  101. } else if (typeof prop === 'function') {
  102. result = prop(this.data.slice(row, row + 1)[0]);
  103. } else {
  104. result = dataRow[prop];
  105. }
  106. }
  107. return result;
  108. }
  109. /**
  110. * Returns source data by passed range.
  111. *
  112. * @param {Object} start Object with `row` and `col` keys.
  113. * @param {Object} end Object with `row` and `col` keys.
  114. * @param {Boolean} [toArray=false] If `true` return source data as an array of arrays even when source data was provided
  115. * in another format.
  116. * @returns {Array}
  117. */
  118. getByRange(start, end, toArray = false) {
  119. let startRow = Math.min(start.row, end.row);
  120. let startCol = Math.min(start.col, end.col);
  121. let endRow = Math.max(start.row, end.row);
  122. let endCol = Math.max(start.col, end.col);
  123. let result = [];
  124. rangeEach(startRow, endRow, (currentRow) => {
  125. let row = this.getAtRow(currentRow);
  126. let newRow;
  127. if (this.dataType === 'array') {
  128. newRow = row.slice(startCol, endCol + 1);
  129. } else if (this.dataType === 'object') {
  130. newRow = toArray ? [] : {};
  131. rangeEach(startCol, endCol, (column) => {
  132. let prop = this.colToProp(column);
  133. if (toArray) {
  134. newRow.push(row[prop]);
  135. } else {
  136. newRow[prop] = row[prop];
  137. }
  138. });
  139. }
  140. result.push(newRow);
  141. });
  142. return result;
  143. }
  144. /**
  145. * Count number of rows.
  146. *
  147. * @returns {Number}
  148. */
  149. countRows() {
  150. return Array.isArray(this.data) ? this.data.length : 0;
  151. }
  152. /**
  153. * Count number of columns.
  154. *
  155. * @returns {Number}
  156. */
  157. countColumns() {
  158. let result = 0;
  159. if (Array.isArray(this.data)) {
  160. if (this.dataType === 'array') {
  161. result = this.data[0].length;
  162. } else if (this.dataType === 'object') {
  163. result = Object.keys(this.data[0]).length;
  164. }
  165. }
  166. return result;
  167. }
  168. /**
  169. * Destroy instance.
  170. */
  171. destroy() {
  172. this.data = null;
  173. this.hot = null;
  174. }
  175. }
  176. export default DataSource;