Skip to content

Commit

Permalink
feat(lt-body): Preliminary Vertical collection integration (#483)
Browse files Browse the repository at this point in the history
* Setup sample app

* Modifying rendering when using native scrollbar

* Working state with dynamic height

* Vertical Collection with fixed width columns

So we don't have to handle resize events for now

* Update README

* Fix ESLint

* eslint

* Fixup CSS alignment issues

* Fixup deps

* Update to vertical-collection beta.9

* Updated v-c usage to reflect new APIs

Fix alignment issue of header not respecting the padding of it's container
  • Loading branch information
alexander-alvarez authored and buschtoens committed Nov 21, 2017
1 parent 0edf5d0 commit 7feb748
Show file tree
Hide file tree
Showing 14 changed files with 379 additions and 68 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ A lightweight contextual component based table addon that follows Ember's action
- Easy table manipulation
- Easy override to table header, body, and footer
- Contextual component for header, body, and footer, as well as loading, no data, and expanded row
- **EXPERIMENTAL** Occlusion rendering leveraging [vertical-collection](https://github.com/html-next/vertical-collection). See [Demo](http://offirgolan.github.io/ember-light-table/#/cookbook/occlusion-rendering).

## Installation

Expand Down
27 changes: 25 additions & 2 deletions addon/components/light-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function intersections(array1, array2) {

const LightTable = Component.extend({
layout,
classNameBindings: [':ember-light-table'],
classNameBindings: [':ember-light-table', 'occlusion'],
attributeBindings: ['style'],

media: service(),
Expand Down Expand Up @@ -159,6 +159,27 @@ const LightTable = Component.extend({
*/
breakpoints: null,

/**
* Toggles occlusion rendering functionality. Currently experimental.
* If set to true, you must set {{#crossLink 't.body/estimatedRowHeight:property'}}{{/crossLink}} to
* something other than the default value.
*
* @property occlusion
* @type Boolean
* @default False
*/
occlusion: false,

/**
* Estimated size of a row. Used in `vertical-collection` to determine roughly the number
* of rows exist out of the viewport.
*
* @property estimatedRowHeight
* @type Number
* @default false
*/
estimatedRowHeight: 0,

/**
* Table component shared options
*
Expand All @@ -170,7 +191,9 @@ const LightTable = Component.extend({
return {
height: this.get('height'),
fixedHeader: false,
fixedFooter: false
fixedFooter: false,
occlusion: this.get('occlusion'),
estimatedRowHeight: this.get('estimatedRowHeight')
};
}).readOnly(),

Expand Down
27 changes: 24 additions & 3 deletions addon/components/lt-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,12 +316,35 @@ export default Component.extend({
this.setupScrollOffset();
},

didInsertElement() {
this._super(...arguments);
if (this.get('sharedOptions.occlusion')) {
this._setupScrollAreaDimensions();
}
},

destroy() {
this._super(...arguments);
run.cancel(this._checkTargetOffsetTimer);
run.cancel(this._setTargetOffsetTimer);
},

/**
* Calculates the available height remaining in the body of the table by taking the table height defined
* on the light table component and subtracting the rendered height of the header.
* May need to extend this to include the footer.
*
* @method _setupScrollAreaDimensions
* @private
*/
_setupScrollAreaDimensions() {
const lightTableContainer = this.element.parentElement;
const { height: totalHeight } = lightTableContainer.getBoundingClientRect();
const headerElem = lightTableContainer.querySelector('.lt-head-wrap');
const { height: headerHeight } = headerElem.getBoundingClientRect();
this.set('height', totalHeight - headerHeight);
},

_setupVirtualScrollbar() {
let { fixedHeader, fixedFooter } = this.get('sharedOptions');
this.set('useVirtualScrollbar', fixedHeader || fixedFooter);
Expand Down Expand Up @@ -423,9 +446,7 @@ export default Component.extend({

if (canSelect) {
if (e.shiftKey && multiSelect) {
rows
.slice(Math.min(currIndex, prevIndex), Math.max(currIndex, prevIndex) + 1)
.forEach((r) => r.set('selected', !isSelected));
rows.slice(Math.min(currIndex, prevIndex), Math.max(currIndex, prevIndex) + 1).forEach((r) => r.set('selected', !isSelected));
} else if ((!multiSelectRequiresKeyboard || (e.ctrlKey || e.metaKey)) && multiSelect) {
row.toggleProperty('selected');
} else {
Expand Down
22 changes: 22 additions & 0 deletions addon/styles/addon.css
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,28 @@
flex: 1 0 auto;
}

.ember-light-table .lt-scrollable.vertical-collection {
overflow-y: auto;
}

/* This is for when useVirtualScrollbar is disabled */
.ember-light-table.occlusion .lt-head-wrap {
padding-right: 14px;
}

.ember-light-table.occlusion .lt-head-wrap table {
display: inline
}

.ember-light-table vertical-collection {
display: table;
table-layout: fixed;
}

.ember-light-table vertical-collection occluded-content:first-of-type {
display: table-caption;
}

.ember-light-table .align-left {
text-align: left;
}
Expand Down
139 changes: 100 additions & 39 deletions addon/templates/components/lt-body.hbs
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
{{#with (hash
row=(or rowComponent (component 'lt-row'))
spanned-row=(or spannedRowComponent (component 'lt-spanned-row'))
infinity=(or infinityComponent (component 'lt-infinity'))
) as |lt|
row=(or rowComponent (component 'lt-row'))
spanned-row=(or spannedRowComponent (component 'lt-spanned-row'))
infinity=(or infinityComponent (component 'lt-infinity'))
) as |lt|
}}
{{#lt-scrollable
tagName=''
virtualScrollbar=useVirtualScrollbar
autoHide=autoHideScrollbar
scrollTo=targetScrollOffset
onScrollY=(action 'onScroll')
}}
<div id={{concat tableId '_inline_head'}} class="lt-inline lt-head"></div>

<table class={{tableClassNames}}>
<tbody class="lt-body">
{{#unless sharedOptions.occlusion}}
{{#lt-scrollable
tagName=''
virtualScrollbar=useVirtualScrollbar
autoHide=autoHideScrollbar
scrollTo=targetScrollOffset
onScrollY=(action 'onScroll')
}}
<div id={{concat tableId '_inline_head'}} class="lt-inline lt-head"></div>

<table class={{tableClassNames}}>
<tbody class="lt-body">
{{#if enableScaffolding}}
<tr class="lt-scaffolding-row">
{{#each columns as |column|}}
Expand All @@ -28,36 +29,96 @@
{{else}}
{{#each rows as |row|}}
{{lt.row row columns
data-row-id=row.rowId
table=table
tableActions=tableActions
extra=extra
enableScaffolding=enableScaffolding
canExpand=canExpand
canSelect=canSelect
click=(action 'onRowClick' row)
doubleClick=(action 'onRowDoubleClick' row)}}
data-row-id=row.rowId
table=table
tableActions=tableActions
extra=extra
enableScaffolding=enableScaffolding
canExpand=canExpand
canSelect=canSelect
click=(action 'onRowClick' row)
doubleClick=(action 'onRowDoubleClick' row)}}

{{yield (hash
expanded-row=(component lt.spanned-row classes='lt-expanded-row' colspan=colspan yield=row visible=row.expanded)
loader=(component lt.spanned-row visible=false)
no-data=(component lt.spanned-row visible=false)
) rows}}
expanded-row=(component lt.spanned-row classes='lt-expanded-row' colspan=colspan yield=row visible=row.expanded)
loader=(component lt.spanned-row visible=false)
no-data=(component lt.spanned-row visible=false)
) rows}}
{{/each}}

{{yield (hash
loader=(component lt.spanned-row classes='lt-is-loading' colspan=colspan)
no-data=(component lt.spanned-row classes='lt-no-data' colspan=colspan)
expanded-row=(component lt.spanned-row visible=false)
) rows}}
loader=(component lt.spanned-row classes='lt-is-loading' colspan=colspan)
no-data=(component lt.spanned-row classes='lt-no-data' colspan=colspan)
expanded-row=(component lt.spanned-row visible=false)
) rows}}
{{/if}}
</tbody>
</table>

{{#if onScrolledToBottom}}
{{lt.infinity rows=rows onScrolledToBottom=onScrolledToBottom scrollBuffer=scrollBuffer}}
{{/if}}

<div id={{concat tableId '_inline_foot'}} class="lt-inline lt-foot"></div>
{{/lt-scrollable}}
{{else}}
<div class="lt-scrollable tse-scrollable vertical-collection" style="{{html-safe (concat 'height:' height 'px')}}">
<div id="{{concat tableId '_inline_head'}}" class="lt-inline lt-head"></div>

<table class={{tableClassNames}}>
<tbody class="lt-body">
{{#if enableScaffolding}}
<tr class="lt-scaffolding-row">
{{#each columns as |column|}}
<td
style={{html-safe (if column.width (concat 'width: ' column.width))}} class="lt-scaffolding"></td>
{{/each}}
</tr>
{{/if}}

{{#if overwrite}}
{{yield columns rows}}
{{else}}
{{#vertical-collection
rows
tagName='vertical-collection'
estimateHeight=sharedOptions.estimatedRowHeight
containerSelector='.lt-scrollable'
as |row index|
}}
{{lt.row row columns
data-row-id=row.rowId
table=table
tableActions=tableActions
extra=extra
enableScaffolding=enableScaffolding
canExpand=canExpand
canSelect=canSelect
click=(action 'onRowClick' row)
doubleClick=(action 'onRowDoubleClick' row)}}

{{yield (hash
expanded-row=(component lt.spanned-row classes='lt-expanded-row' colspan=colspan yield=row visible=row.expanded)
loader=(component lt.spanned-row visible=false)
no-data=(component lt.spanned-row visible=false)
) rows}}

{{/vertical-collection}}
{{yield (hash
loader=(component lt.spanned-row classes='lt-is-loading' colspan=colspan)
no-data=(component lt.spanned-row classes='lt-no-data' colspan=colspan)
expanded-row=(component lt.spanned-row visible=false)
) rows}}
{{/if}}
</tbody>
</table>
</tbody>
</table>

{{#if onScrolledToBottom}}
{{lt.infinity rows=rows onScrolledToBottom=onScrolledToBottom scrollBuffer=scrollBuffer}}
{{/if}}
{{!--#if onScrolledToBottom}} TODO figure out how to use the scrollbuffer property for infinite loading
lastReached=onScrolledToBottom
{{lt.infinity rows=rows onScrolledToBottom=onScrolledToBottom scrollBuffer=scrollBuffer}}
{{/if --}}

<div id={{concat tableId '_inline_foot'}} class="lt-inline lt-foot"></div>
{{/lt-scrollable}}
<div id="{{concat tableId '_inline_foot'}}" class="lt-inline lt-foot"></div>
</div>
{{/unless}}
{{/with}}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"test": "ember try:each"
},
"dependencies": {
"@html-next/vertical-collection": "^1.0.0-beta.9",
"ember-cli-babel": "^6.6.0",
"ember-cli-htmlbars": "^2.0.2",
"ember-cli-string-helpers": "^1.5.0",
Expand Down
44 changes: 44 additions & 0 deletions tests/dummy/app/components/cookbook/occluded-table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// BEGIN-SNIPPET occluded-table
import Component from '@ember/component';
import TableCommon from '../../mixins/table-common';
import { computed } from '@ember/object';

export default Component.extend(TableCommon, {
limit: 100,
columns: computed(function() {
return [{
label: 'Avatar',
valuePath: 'avatar',
width: '60px',
sortable: false,
cellComponent: 'user-avatar'
}, {
label: 'First Name',
valuePath: 'firstName',
width: '150px'
}, {
label: 'Last Name',
valuePath: 'lastName',
width: '150px'
}, {
label: 'Address',
valuePath: 'address',
width: '150px'
}, {
label: 'State',
valuePath: 'state',
width: '100px'
}, {
label: 'Country',
valuePath: 'country',
width: '100px'
}];
}),

init() {
this._super(...arguments);
this.set('page', 1);
this.get('fetchRecords').perform();
}
});
// END-SNIPPET
5 changes: 3 additions & 2 deletions tests/dummy/app/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ Router.map(function() {

this.route('cookbook', function() {
this.route('client-side');
this.route('pagination');
this.route('custom-row');
this.route('table-actions');
this.route('horizontal-scrolling');
this.route('occlusion-rendering');
this.route('pagination');
this.route('table-actions');
this.route('custom-sort-icon');
});
});
Expand Down
1 change: 1 addition & 0 deletions tests/dummy/app/routes/cookbook/occlusion-rendering.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from '../table-route';
7 changes: 7 additions & 0 deletions tests/dummy/app/styles/table.less
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,10 @@ tfoot {
}
}
}


.ember-light-table.occlusion {
.lt-row td {
vertical-align: middle;
}
}
7 changes: 5 additions & 2 deletions tests/dummy/app/templates/application.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,15 @@
{{#link-to 'cookbook.horizontal-scrolling' tagName="li"}}
{{link-to 'Horizontal Scrolling' 'cookbook.horizontal-scrolling'}}
{{/link-to}}
{{#link-to 'cookbook.table-actions' tagName="li"}}
{{link-to 'Table Actions' 'cookbook.table-actions'}}
{{#link-to 'cookbook.occlusion-rendering' tagName="li"}}
{{link-to 'Occlusion Rendering' 'cookbook.occlusion-rendering'}}
{{/link-to}}
{{#link-to 'cookbook.pagination' tagName="li"}}
{{link-to 'Pagination' 'cookbook.pagination'}}
{{/link-to}}
{{#link-to 'cookbook.table-actions' tagName="li"}}
{{link-to 'Table Actions' 'cookbook.table-actions'}}
{{/link-to}}
{{#link-to 'cookbook.custom-sort-icon' tagName="li"}}
{{link-to 'Custom Sort Icon' 'cookbook.custom-sort-icon'}}
{{/link-to}}
Expand Down
Loading

0 comments on commit 7feb748

Please sign in to comment.