diff --git a/package.json b/package.json index b8bfbfb..946dc3e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "cy:open": "cypress open", "cy:run": "cypress run", "test": "start-server-and-test cy:server http://localhost:8989 cy:run", + "test-local": "start-server-and-test cy:server http://localhost:8989 cy:open", "travis-deploy-once": "travis-deploy-once", "semantic-release": "semantic-release", "lint": "eslint src", @@ -64,7 +65,7 @@ }, "homepage": "https://frappe.github.io/datatable", "dependencies": { - "clusterize.js": "^0.18.0", + "hyperlist": "^1.0.0-beta", "lodash": "^4.17.5", "sortablejs": "^1.7.0" }, diff --git a/src/body-renderer.js b/src/body-renderer.js index 33348fc..d092601 100644 --- a/src/body-renderer.js +++ b/src/body-renderer.js @@ -1,6 +1,5 @@ -import Clusterize from 'clusterize.js'; +import HyperList from 'hyperlist'; import $ from './dom'; -import { nextTick } from './utils'; export default class BodyRenderer { constructor(instance) { @@ -11,59 +10,45 @@ export default class BodyRenderer { this.cellmanager = instance.cellmanager; this.bodyScrollable = instance.bodyScrollable; this.log = instance.log; - this.appendRemainingData = nextTick(this.appendRemainingData, this); + } + + renderRows(rows) { + let config = { + itemHeight: 40, + total: rows.length, + generate: (index) => { + const el = document.createElement('div'); + const rowHTML = this.rowmanager.getRowHTML(rows[index], rows[index].meta); + el.innerHTML = rowHTML; + return el.children[0]; + } + }; + this.hyperlist.refresh($('.dt-body', this.bodyScrollable), config); } render() { - if (this.options.clusterize) { - this.renderBodyWithClusterize(); - } else { - this.renderBodyHTML(); - } - } - - renderBodyHTML() { const rows = this.datamanager.getRowsForView(); - this.bodyScrollable.innerHTML = this.getBodyHTML(rows); - this.instance.setDimensions(); - this.restoreState(); - } + let config = { + itemHeight: 40, + total: rows.length, + generate: (index) => { + const el = document.createElement('div'); + const rowHTML = this.rowmanager.getRowHTML(rows[index], rows[index].meta); + el.innerHTML = rowHTML; + return el.children[0]; + } + }; - renderBodyWithClusterize() { - // first page - const rows = this.datamanager.getRowsForView(0, 20); - let initialData = this.getDataForClusterize(rows); - - if (initialData.length === 0) { - initialData = [this.getNoDataHTML()]; - } - - if (!this.clusterize) { - // empty body - this.bodyScrollable.innerHTML = this.getBodyHTML([]); - - // first 20 rows will appended - // rest of them in nextTick - this.clusterize = new Clusterize({ - rows: initialData, - scrollElem: this.bodyScrollable, - contentElem: $('tbody', this.bodyScrollable), - callbacks: { - clusterChanged: () => this.restoreState() - }, - /* eslint-disable */ - show_no_data_row: false, - /* eslint-enable */ - }); - - // setDimensions requires atleast 1 row to exist in dom - this.instance.setDimensions(); + if (!this.hyperlist) { + this.bodyScrollable.innerHTML = '
'; + this.hyperlist = new HyperList($('.dt-body', this.bodyScrollable), config); } else { - this.clusterize.update(initialData); + this.renderRows(rows); } - this.appendRemainingData(); + // setDimensions requires atleast 1 row to exist in dom + this.instance.setDimensions(); } restoreState() { @@ -73,12 +58,6 @@ export default class BodyRenderer { this.cellmanager.focusCellOnClusterChanged(); } - appendRemainingData() { - const rows = this.datamanager.getRowsForView(20); - const data = this.getDataForClusterize(rows); - this.clusterize.append(data); - } - showToastMessage(message, hideAfter) { this.instance.toastMessage.innerHTML = this.getToastMessageHTML(message); @@ -99,11 +78,11 @@ export default class BodyRenderer { getBodyHTML(rows) { return ` - - +
+
${rows.map(row => this.rowmanager.getRowHTML(row, row.meta)).join('')} -
-
+ + `; } diff --git a/src/cellmanager.js b/src/cellmanager.js index e251534..4f1be22 100644 --- a/src/cellmanager.js +++ b/src/cellmanager.js @@ -749,9 +749,9 @@ export default class CellManager { ].join(' '); return ` - +
${this.getCellContent(cell)} - +
`; } diff --git a/src/columnmanager.js b/src/columnmanager.js index d443dd9..1cefd6e 100644 --- a/src/columnmanager.js +++ b/src/columnmanager.js @@ -17,14 +17,15 @@ export default class ColumnManager { 'style', 'wrapper', 'rowmanager', - 'bodyScrollable' + 'bodyScrollable', + 'bodyRenderer' ]); this.bindEvents(); } renderHeader() { - this.header.innerHTML = ''; + this.header.innerHTML = '
'; this.refreshHeader(); } @@ -32,7 +33,7 @@ export default class ColumnManager { const columns = this.datamanager.getColumns(); // refresh html - $('thead', this.header).innerHTML = this.getHeaderHTML(columns); + $('div', this.header).innerHTML = this.getHeaderHTML(columns); this.$filterRow = $('.dt-row-filter', this.header); if (this.$filterRow) { @@ -282,11 +283,10 @@ export default class ColumnManager { applyFilter(keyword, colIndex) { this.datamanager.filterRows(keyword, colIndex) .then(({ - rowsToHide, rowsToShow }) => { - this.rowmanager.hideRows(rowsToHide); - this.rowmanager.showRows(rowsToShow); + const rows = rowsToShow.map(rowIndex => this.datamanager.getRow(rowIndex)); + this.bodyRenderer.renderRows(rows); }); } diff --git a/src/datatable.js b/src/datatable.js index 8abebee..391a592 100644 --- a/src/datatable.js +++ b/src/datatable.js @@ -69,8 +69,8 @@ class DataTable { prepareDom() { this.wrapper.innerHTML = `
- -
+
+
diff --git a/src/rowmanager.js b/src/rowmanager.js index b6a1674..50ad350 100644 --- a/src/rowmanager.js +++ b/src/rowmanager.js @@ -279,9 +279,9 @@ export default class RowManager { } return ` - +
${row.map(cell => this.cellmanager.getCellHTML(cell)).join('')} - +
`; } diff --git a/src/style.css b/src/style.css index 8dee290..ebb85d0 100644 --- a/src/style.css +++ b/src/style.css @@ -43,7 +43,7 @@ } .dt-scrollable { - max-height: 40vw; + height: 40vw; overflow: auto; border-bottom: 1px solid var(--dt-border-color); @@ -60,6 +60,8 @@ } .dt-row { + display: flex; + &--highlight .dt-cell { background-color: var(--dt-selection-highlight-color); } @@ -75,6 +77,8 @@ .dt-cell { border: 1px solid var(--dt-border-color); + border-bottom: none; + border-right: none; position: relative; outline: none; padding: 0; @@ -141,6 +145,10 @@ background-color: var(--dt-header-cell-bg); } + &--header:last-child { + border-right: 1px solid var(--dt-border-color); + } + &--header &__content { padding-right: var(--dt-spacer-3); font-weight: bold; diff --git a/src/style.js b/src/style.js index b902202..5cda80b 100644 --- a/src/style.js +++ b/src/style.js @@ -119,33 +119,16 @@ export default class Style { } setDimensions() { - this.setHeaderStyle(); - this.setupMinWidth(); this.setupNaturalColumnWidth(); this.setupColumnWidth(); this.distributeRemainingWidth(); this.setColumnStyle(); this.compensateScrollbarWidth(); - this.setDefaultCellHeight(); this.setBodyStyle(); } - setHeaderStyle() { - if (this.options.layout === 'fluid') { - // setting width as 0 will ensure that the - // header doesn't take the available space - $.style(this.header, { - width: 0 - }); - } - - $.style(this.header, { - margin: 0 - }); - } - setupMinWidth() { $.each('.dt-cell--header', this.header).map(col => { const { colIndex } = $.data(col); @@ -228,7 +211,7 @@ export default class Style { } compensateScrollbarWidth() { - if (!$.hasVerticalOverflow(this.bodyScrollable)) return; + if (!$.hasVerticalOverflow($('.dt-body', this.bodyScrollable))) return; requestAnimationFrame(() => { const scrollbarWidth = $.scrollbarWidth(); @@ -313,26 +296,9 @@ export default class Style { width: width + 'px' }); - const $body = $('.dt-body', this.bodyScrollable); - - if ($body) { - $.style($body, { - height: '0px' - }); - - $.style($('tbody', $body), { - height: '100%' - }); - } - $.style(this.bodyScrollable, { marginTop: $.style(this.header, 'height') + 'px' }); - - $.style($('table', this.bodyScrollable), { - margin: 0, - width: '100%' - }); }); } diff --git a/yarn.lock b/yarn.lock index eec30ca..956f5ea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1493,11 +1493,6 @@ clone@^1.0.2: resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" integrity sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8= -clusterize.js@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/clusterize.js/-/clusterize.js-0.18.0.tgz#32dce7267c5e934bfb205ba65a98760005041331" - integrity sha512-13AqtsPStx5OawyggucdPawJaJmPl56HbG32Urya79VE39T7ZlpgVUGIOPwr9TIwf/duZAXjhXDQxC2eiMe6AA== - co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -3331,6 +3326,11 @@ https-proxy-agent@^2.2.0, https-proxy-agent@^2.2.1: agent-base "^4.1.0" debug "^3.1.0" +hyperlist@^1.0.0-beta: + version "1.0.0-beta" + resolved "https://registry.yarnpkg.com/hyperlist/-/hyperlist-1.0.0-beta.tgz#2cbbd77f4498c2ecc290b7f3c6745b3f0288247e" + integrity sha1-LLvXf0SYwuzCkLfzxnRbPwKIJH4= + iconv-lite@^0.4.17: version "0.4.21" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798"