ghostTable.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. import { addClass, outerHeight, outerWidth } from './../helpers/dom/element';
  4. import { arrayEach } from './../helpers/array';
  5. /**
  6. * @class GhostTable
  7. * @util
  8. */
  9. var GhostTable = function () {
  10. function GhostTable(hotInstance) {
  11. _classCallCheck(this, GhostTable);
  12. /**
  13. * Handsontable instance.
  14. *
  15. * @type {Core}
  16. */
  17. this.hot = hotInstance;
  18. /**
  19. * Container element where every table will be injected.
  20. *
  21. * @type {HTMLElement|null}
  22. */
  23. this.container = null;
  24. /**
  25. * Flag which determine is table was injected to DOM.
  26. *
  27. * @type {Boolean}
  28. */
  29. this.injected = false;
  30. /**
  31. * Added rows collection.
  32. *
  33. * @type {Array}
  34. */
  35. this.rows = [];
  36. /**
  37. * Added columns collection.
  38. *
  39. * @type {Array}
  40. */
  41. this.columns = [];
  42. /**
  43. * Samples prepared for calculations.
  44. *
  45. * @type {Map}
  46. * @default {null}
  47. */
  48. this.samples = null;
  49. /**
  50. * Ghost table settings.
  51. *
  52. * @type {Object}
  53. * @default {Object}
  54. */
  55. this.settings = {
  56. useHeaders: true
  57. };
  58. }
  59. /**
  60. * Add row.
  61. *
  62. * @param {Number} row Row index.
  63. * @param {Map} samples Samples Map object.
  64. */
  65. _createClass(GhostTable, [{
  66. key: 'addRow',
  67. value: function addRow(row, samples) {
  68. if (this.columns.length) {
  69. throw new Error('Doesn\'t support multi-dimensional table');
  70. }
  71. if (!this.rows.length) {
  72. this.container = this.createContainer(this.hot.rootElement.className);
  73. }
  74. var rowObject = { row: row };
  75. this.rows.push(rowObject);
  76. this.samples = samples;
  77. this.table = this.createTable(this.hot.table.className);
  78. this.table.colGroup.appendChild(this.createColGroupsCol());
  79. this.table.tr.appendChild(this.createRow(row));
  80. this.container.container.appendChild(this.table.fragment);
  81. rowObject.table = this.table.table;
  82. }
  83. /**
  84. * Add a row consisting of the column headers.
  85. */
  86. }, {
  87. key: 'addColumnHeadersRow',
  88. value: function addColumnHeadersRow(samples) {
  89. if (this.hot.getColHeader(0) != null) {
  90. var rowObject = { row: -1 };
  91. this.rows.push(rowObject);
  92. this.container = this.createContainer(this.hot.rootElement.className);
  93. this.samples = samples;
  94. this.table = this.createTable(this.hot.table.className);
  95. this.table.colGroup.appendChild(this.createColGroupsCol());
  96. this.table.tHead.appendChild(this.createColumnHeadersRow());
  97. this.container.container.appendChild(this.table.fragment);
  98. rowObject.table = this.table.table;
  99. }
  100. }
  101. /**
  102. * Add column.
  103. *
  104. * @param {Number} column Column index.
  105. * @param {Map} samples Samples Map object.
  106. */
  107. }, {
  108. key: 'addColumn',
  109. value: function addColumn(column, samples) {
  110. if (this.rows.length) {
  111. throw new Error('Doesn\'t support multi-dimensional table');
  112. }
  113. if (!this.columns.length) {
  114. this.container = this.createContainer(this.hot.rootElement.className);
  115. }
  116. var columnObject = { col: column };
  117. this.columns.push(columnObject);
  118. this.samples = samples;
  119. this.table = this.createTable(this.hot.table.className);
  120. if (this.getSetting('useHeaders') && this.hot.getColHeader(column) !== null) {
  121. this.hot.view.appendColHeader(column, this.table.th);
  122. }
  123. this.table.tBody.appendChild(this.createCol(column));
  124. this.container.container.appendChild(this.table.fragment);
  125. columnObject.table = this.table.table;
  126. }
  127. /**
  128. * Get calculated heights.
  129. *
  130. * @param {Function} callback Callback which will be fired for each calculated row.
  131. */
  132. }, {
  133. key: 'getHeights',
  134. value: function getHeights(callback) {
  135. if (!this.injected) {
  136. this.injectTable();
  137. }
  138. arrayEach(this.rows, function (row) {
  139. // -1 <- reduce border-top from table
  140. callback(row.row, outerHeight(row.table) - 1);
  141. });
  142. }
  143. /**
  144. * Get calculated widths.
  145. *
  146. * @param {Function} callback Callback which will be fired for each calculated column.
  147. */
  148. }, {
  149. key: 'getWidths',
  150. value: function getWidths(callback) {
  151. if (!this.injected) {
  152. this.injectTable();
  153. }
  154. arrayEach(this.columns, function (column) {
  155. callback(column.col, outerWidth(column.table));
  156. });
  157. }
  158. /**
  159. * Set the Ghost Table settings to the provided object.
  160. *
  161. * @param {Object} settings New Ghost Table Settings
  162. */
  163. }, {
  164. key: 'setSettings',
  165. value: function setSettings(settings) {
  166. this.settings = settings;
  167. }
  168. /**
  169. * Set a single setting of the Ghost Table.
  170. *
  171. * @param {String} name Setting name.
  172. * @param {*} value Setting value.
  173. */
  174. }, {
  175. key: 'setSetting',
  176. value: function setSetting(name, value) {
  177. if (!this.settings) {
  178. this.settings = {};
  179. }
  180. this.settings[name] = value;
  181. }
  182. /**
  183. * Get the Ghost Table settings.
  184. *
  185. * @returns {Object|null}
  186. */
  187. }, {
  188. key: 'getSettings',
  189. value: function getSettings() {
  190. return this.settings;
  191. }
  192. /**
  193. * Get a single Ghost Table setting.
  194. *
  195. * @param {String} name
  196. * @returns {Boolean|null}
  197. */
  198. }, {
  199. key: 'getSetting',
  200. value: function getSetting(name) {
  201. if (this.settings) {
  202. return this.settings[name];
  203. }
  204. return null;
  205. }
  206. /**
  207. * Create colgroup col elements.
  208. *
  209. * @returns {DocumentFragment}
  210. */
  211. }, {
  212. key: 'createColGroupsCol',
  213. value: function createColGroupsCol() {
  214. var _this = this;
  215. var d = document;
  216. var fragment = d.createDocumentFragment();
  217. if (this.hot.hasRowHeaders()) {
  218. fragment.appendChild(this.createColElement(-1));
  219. }
  220. this.samples.forEach(function (sample) {
  221. arrayEach(sample.strings, function (string) {
  222. fragment.appendChild(_this.createColElement(string.col));
  223. });
  224. });
  225. return fragment;
  226. }
  227. /**
  228. * Create table row element.
  229. *
  230. * @param {Number} row Row index.
  231. * @returns {DocumentFragment} Returns created table row elements.
  232. */
  233. }, {
  234. key: 'createRow',
  235. value: function createRow(row) {
  236. var _this2 = this;
  237. var d = document;
  238. var fragment = d.createDocumentFragment();
  239. var th = d.createElement('th');
  240. if (this.hot.hasRowHeaders()) {
  241. this.hot.view.appendRowHeader(row, th);
  242. fragment.appendChild(th);
  243. }
  244. this.samples.forEach(function (sample) {
  245. arrayEach(sample.strings, function (string) {
  246. var column = string.col;
  247. var cellProperties = _this2.hot.getCellMeta(row, column);
  248. cellProperties.col = column;
  249. cellProperties.row = row;
  250. var renderer = _this2.hot.getCellRenderer(cellProperties);
  251. var td = d.createElement('td');
  252. renderer(_this2.hot, td, row, column, _this2.hot.colToProp(column), string.value, cellProperties);
  253. fragment.appendChild(td);
  254. });
  255. });
  256. return fragment;
  257. }
  258. }, {
  259. key: 'createColumnHeadersRow',
  260. value: function createColumnHeadersRow() {
  261. var _this3 = this;
  262. var d = document;
  263. var fragment = d.createDocumentFragment();
  264. if (this.hot.hasRowHeaders()) {
  265. var th = d.createElement('th');
  266. this.hot.view.appendColHeader(-1, th);
  267. fragment.appendChild(th);
  268. }
  269. this.samples.forEach(function (sample) {
  270. arrayEach(sample.strings, function (string) {
  271. var column = string.col;
  272. var th = d.createElement('th');
  273. _this3.hot.view.appendColHeader(column, th);
  274. fragment.appendChild(th);
  275. });
  276. });
  277. return fragment;
  278. }
  279. /**
  280. * Create table column elements.
  281. *
  282. * @param {Number} column Column index.
  283. * @returns {DocumentFragment} Returns created column table column elements.
  284. */
  285. }, {
  286. key: 'createCol',
  287. value: function createCol(column) {
  288. var _this4 = this;
  289. var d = document;
  290. var fragment = d.createDocumentFragment();
  291. this.samples.forEach(function (sample) {
  292. arrayEach(sample.strings, function (string) {
  293. var row = string.row;
  294. var cellProperties = _this4.hot.getCellMeta(row, column);
  295. cellProperties.col = column;
  296. cellProperties.row = row;
  297. var renderer = _this4.hot.getCellRenderer(cellProperties);
  298. var td = d.createElement('td');
  299. var tr = d.createElement('tr');
  300. renderer(_this4.hot, td, row, column, _this4.hot.colToProp(column), string.value, cellProperties);
  301. tr.appendChild(td);
  302. fragment.appendChild(tr);
  303. });
  304. });
  305. return fragment;
  306. }
  307. /**
  308. * Remove table from document and reset internal state.
  309. */
  310. }, {
  311. key: 'clean',
  312. value: function clean() {
  313. this.rows.length = 0;
  314. this.rows[-1] = void 0;
  315. this.columns.length = 0;
  316. if (this.samples) {
  317. this.samples.clear();
  318. }
  319. this.samples = null;
  320. this.removeTable();
  321. }
  322. /**
  323. * Inject generated table into document.
  324. *
  325. * @param {HTMLElement} [parent=null]
  326. */
  327. }, {
  328. key: 'injectTable',
  329. value: function injectTable() {
  330. var parent = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
  331. if (!this.injected) {
  332. (parent || this.hot.rootElement).appendChild(this.container.fragment);
  333. this.injected = true;
  334. }
  335. }
  336. /**
  337. * Remove table from document.
  338. */
  339. }, {
  340. key: 'removeTable',
  341. value: function removeTable() {
  342. if (this.injected && this.container.container.parentNode) {
  343. this.container.container.parentNode.removeChild(this.container.container);
  344. this.container = null;
  345. this.injected = false;
  346. }
  347. }
  348. /**
  349. * Create col element.
  350. *
  351. * @param {Number} column Column index.
  352. * @returns {HTMLElement}
  353. */
  354. }, {
  355. key: 'createColElement',
  356. value: function createColElement(column) {
  357. var d = document;
  358. var col = d.createElement('col');
  359. col.style.width = this.hot.view.wt.wtTable.getStretchedColumnWidth(column) + 'px';
  360. return col;
  361. }
  362. /**
  363. * Create table element.
  364. *
  365. * @param {String} className
  366. * @returns {Object}
  367. */
  368. }, {
  369. key: 'createTable',
  370. value: function createTable() {
  371. var className = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  372. var d = document;
  373. var fragment = d.createDocumentFragment();
  374. var table = d.createElement('table');
  375. var tHead = d.createElement('thead');
  376. var tBody = d.createElement('tbody');
  377. var colGroup = d.createElement('colgroup');
  378. var tr = d.createElement('tr');
  379. var th = d.createElement('th');
  380. if (this.isVertical()) {
  381. table.appendChild(colGroup);
  382. }
  383. if (this.isHorizontal()) {
  384. tr.appendChild(th);
  385. tHead.appendChild(tr);
  386. table.style.tableLayout = 'auto';
  387. table.style.width = 'auto';
  388. }
  389. table.appendChild(tHead);
  390. if (this.isVertical()) {
  391. tBody.appendChild(tr);
  392. }
  393. table.appendChild(tBody);
  394. addClass(table, className);
  395. fragment.appendChild(table);
  396. return { fragment: fragment, table: table, tHead: tHead, tBody: tBody, colGroup: colGroup, tr: tr, th: th };
  397. }
  398. /**
  399. * Create container for tables.
  400. *
  401. * @param {String} className
  402. * @returns {Object}
  403. */
  404. }, {
  405. key: 'createContainer',
  406. value: function createContainer() {
  407. var className = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  408. var d = document;
  409. var fragment = d.createDocumentFragment();
  410. var container = d.createElement('div');
  411. className = 'htGhostTable htAutoSize ' + className.trim();
  412. addClass(container, className);
  413. fragment.appendChild(container);
  414. return { fragment: fragment, container: container };
  415. }
  416. /**
  417. * Checks if table is raised vertically (checking rows).
  418. *
  419. * @returns {Boolean}
  420. */
  421. }, {
  422. key: 'isVertical',
  423. value: function isVertical() {
  424. return !!(this.rows.length && !this.columns.length);
  425. }
  426. /**
  427. * Checks if table is raised horizontally (checking columns).
  428. *
  429. * @returns {Boolean}
  430. */
  431. }, {
  432. key: 'isHorizontal',
  433. value: function isHorizontal() {
  434. return !!(this.columns.length && !this.rows.length);
  435. }
  436. }]);
  437. return GhostTable;
  438. }();
  439. export default GhostTable;