Showing preview only (340K chars total). Download the full file or copy to clipboard to get everything.
Repository: offirgolan/ember-light-table
Branch: master
Commit: c27cd9fa6686
Files: 216
Total size: 289.4 KB
Directory structure:
gitextract_3izqe97e/
├── .editorconfig
├── .ember-cli
├── .eslintignore
├── .eslintrc.js
├── .github/
│ └── workflows/
│ └── ci.yml
├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc.js
├── .template-lintrc.js
├── .tool-versions
├── .watchmanconfig
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── RELEASE.md
├── addon/
│ ├── -private/
│ │ └── global-options.js
│ ├── .gitkeep
│ ├── classes/
│ │ ├── Column.js
│ │ ├── Row.js
│ │ └── Table.js
│ ├── components/
│ │ ├── cells/
│ │ │ ├── base.hbs
│ │ │ └── base.js
│ │ ├── columns/
│ │ │ ├── base.hbs
│ │ │ └── base.js
│ │ ├── light-table.hbs
│ │ ├── light-table.js
│ │ ├── lt-body.hbs
│ │ ├── lt-body.js
│ │ ├── lt-column-resizer.hbs
│ │ ├── lt-column-resizer.js
│ │ ├── lt-foot.hbs
│ │ ├── lt-foot.js
│ │ ├── lt-head.hbs
│ │ ├── lt-head.js
│ │ ├── lt-infinity.hbs
│ │ ├── lt-infinity.js
│ │ ├── lt-row.hbs
│ │ ├── lt-row.js
│ │ ├── lt-scaffolding-row.hbs
│ │ ├── lt-scaffolding-row.js
│ │ ├── lt-scrollable.hbs
│ │ ├── lt-scrollable.js
│ │ ├── lt-spanned-row.hbs
│ │ └── lt-spanned-row.js
│ ├── helpers/
│ │ ├── compute.js
│ │ └── html-safe.js
│ ├── index.js
│ ├── mixins/
│ │ ├── draggable-column.js
│ │ └── table-header.js
│ ├── styles/
│ │ └── addon.css
│ └── utils/
│ ├── closest.js
│ └── css-styleify.js
├── app/
│ ├── .gitkeep
│ ├── components/
│ │ ├── light-table/
│ │ │ ├── cells/
│ │ │ │ └── base.js
│ │ │ └── columns/
│ │ │ └── base.js
│ │ ├── light-table.js
│ │ ├── lt-body.js
│ │ ├── lt-column-resizer.js
│ │ ├── lt-foot.js
│ │ ├── lt-head.js
│ │ ├── lt-infinity.js
│ │ ├── lt-row.js
│ │ ├── lt-scaffolding-row.js
│ │ ├── lt-scrollable.js
│ │ └── lt-spanned-row.js
│ └── helpers/
│ ├── compute.js
│ └── html-safe.js
├── blueprints/
│ ├── cell-type/
│ │ ├── files/
│ │ │ └── app/
│ │ │ └── components/
│ │ │ └── light-table/
│ │ │ └── cells/
│ │ │ └── __name__.js
│ │ └── index.js
│ ├── column-type/
│ │ ├── files/
│ │ │ └── app/
│ │ │ └── components/
│ │ │ └── light-table/
│ │ │ └── columns/
│ │ │ └── __name__.js
│ │ └── index.js
│ └── ember-light-table/
│ └── index.js
├── ember-cli-build.js
├── index.js
├── package.json
├── testem.js
├── tests/
│ ├── dummy/
│ │ ├── app/
│ │ │ ├── adapters/
│ │ │ │ └── application.js
│ │ │ ├── app.js
│ │ │ ├── breakpoints.js
│ │ │ ├── components/
│ │ │ │ ├── .gitkeep
│ │ │ │ ├── base-table.js
│ │ │ │ ├── code-panel.hbs
│ │ │ │ ├── code-panel.js
│ │ │ │ ├── code-snippet.hbs
│ │ │ │ ├── colored-row.js
│ │ │ │ ├── columns/
│ │ │ │ │ ├── draggable-table.hbs
│ │ │ │ │ ├── draggable-table.js
│ │ │ │ │ ├── grouped-table.hbs
│ │ │ │ │ ├── grouped-table.js
│ │ │ │ │ ├── resizable-table.hbs
│ │ │ │ │ └── resizable-table.js
│ │ │ │ ├── cookbook/
│ │ │ │ │ ├── client-side-table.hbs
│ │ │ │ │ ├── client-side-table.js
│ │ │ │ │ ├── custom-row-table.hbs
│ │ │ │ │ ├── custom-row-table.js
│ │ │ │ │ ├── custom-sort-icon-table.hbs
│ │ │ │ │ ├── custom-sort-icon-table.js
│ │ │ │ │ ├── horizontal-scrolling-table.hbs
│ │ │ │ │ ├── horizontal-scrolling-table.js
│ │ │ │ │ ├── index-list.hbs
│ │ │ │ │ ├── occluded-table.hbs
│ │ │ │ │ ├── occluded-table.js
│ │ │ │ │ ├── paginated-table.hbs
│ │ │ │ │ ├── paginated-table.js
│ │ │ │ │ ├── table-actions-table.hbs
│ │ │ │ │ └── table-actions-table.js
│ │ │ │ ├── expanded-row.hbs
│ │ │ │ ├── fa-icon-wrapper.hbs
│ │ │ │ ├── materialize-icon.hbs
│ │ │ │ ├── no-data.hbs
│ │ │ │ ├── responsive-expanded-row.hbs
│ │ │ │ ├── responsive-table.hbs
│ │ │ │ ├── responsive-table.js
│ │ │ │ ├── row-toggle.hbs
│ │ │ │ ├── rows/
│ │ │ │ │ ├── expandable-table.hbs
│ │ │ │ │ ├── expandable-table.js
│ │ │ │ │ ├── selectable-table.hbs
│ │ │ │ │ └── selectable-table.js
│ │ │ │ ├── scrolling-table.hbs
│ │ │ │ ├── scrolling-table.js
│ │ │ │ ├── simple-table.hbs
│ │ │ │ ├── simple-table.js
│ │ │ │ ├── table-loader.hbs
│ │ │ │ ├── user-actions.hbs
│ │ │ │ └── user-avatar.hbs
│ │ │ ├── controllers/
│ │ │ │ ├── .gitkeep
│ │ │ │ └── application.js
│ │ │ ├── helpers/
│ │ │ │ ├── .gitkeep
│ │ │ │ └── classify.js
│ │ │ ├── index.html
│ │ │ ├── models/
│ │ │ │ ├── .gitkeep
│ │ │ │ └── user.js
│ │ │ ├── router.js
│ │ │ ├── routes/
│ │ │ │ ├── .gitkeep
│ │ │ │ ├── columns/
│ │ │ │ │ ├── draggable.js
│ │ │ │ │ ├── grouped.js
│ │ │ │ │ └── resizable.js
│ │ │ │ ├── cookbook/
│ │ │ │ │ ├── custom-row.js
│ │ │ │ │ ├── custom-sort-icon.js
│ │ │ │ │ ├── horizontal-scrolling.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── occlusion-rendering.js
│ │ │ │ │ ├── pagination.js
│ │ │ │ │ ├── sorting.js
│ │ │ │ │ └── table-actions.js
│ │ │ │ ├── cookbook.js
│ │ │ │ ├── index.js
│ │ │ │ ├── responsive.js
│ │ │ │ ├── rows/
│ │ │ │ │ ├── expandable.js
│ │ │ │ │ └── selectable.js
│ │ │ │ ├── scrolling.js
│ │ │ │ └── table-route.js
│ │ │ ├── serializers/
│ │ │ │ └── application.js
│ │ │ ├── styles/
│ │ │ │ ├── app.scss
│ │ │ │ ├── loader.scss
│ │ │ │ └── table.scss
│ │ │ └── templates/
│ │ │ ├── application.hbs
│ │ │ ├── columns/
│ │ │ │ ├── draggable.hbs
│ │ │ │ ├── grouped.hbs
│ │ │ │ └── resizable.hbs
│ │ │ ├── cookbook/
│ │ │ │ ├── client-side.hbs
│ │ │ │ ├── custom-row.hbs
│ │ │ │ ├── custom-sort-icon.hbs
│ │ │ │ ├── horizontal-scrolling.hbs
│ │ │ │ ├── index.hbs
│ │ │ │ ├── occlusion-rendering.hbs
│ │ │ │ ├── pagination.hbs
│ │ │ │ └── table-actions.hbs
│ │ │ ├── index.hbs
│ │ │ ├── responsive.hbs
│ │ │ ├── rows/
│ │ │ │ ├── expandable.hbs
│ │ │ │ └── selectable.hbs
│ │ │ └── scrolling.hbs
│ │ ├── config/
│ │ │ ├── ember-cli-update.json
│ │ │ ├── ember-try.js
│ │ │ ├── environment.js
│ │ │ ├── icons.js
│ │ │ ├── optional-features.json
│ │ │ └── targets.js
│ │ ├── mirage/
│ │ │ ├── config.js
│ │ │ ├── factories/
│ │ │ │ └── user.js
│ │ │ ├── models/
│ │ │ │ └── user.js
│ │ │ ├── scenarios/
│ │ │ │ └── default.js
│ │ │ └── serializers/
│ │ │ └── application.js
│ │ └── public/
│ │ └── robots.txt
│ ├── helpers/
│ │ ├── has-class.js
│ │ ├── index.js
│ │ ├── responsive.js
│ │ └── table-columns.js
│ ├── index.html
│ ├── integration/
│ │ ├── .gitkeep
│ │ ├── components/
│ │ │ ├── light-table/
│ │ │ │ ├── cells/
│ │ │ │ │ └── base-test.js
│ │ │ │ └── columns/
│ │ │ │ └── base-test.js
│ │ │ ├── light-table-occlusion-test.js
│ │ │ ├── light-table-test.js
│ │ │ ├── lt-body-occlusion-test.js
│ │ │ ├── lt-body-test.js
│ │ │ ├── lt-column-resizer-test.js
│ │ │ ├── lt-foot-test.js
│ │ │ ├── lt-head-test.js
│ │ │ ├── lt-infinity-test.js
│ │ │ ├── lt-row-test.js
│ │ │ ├── lt-scaffolding-row-test.js
│ │ │ ├── lt-scrollable-test.js
│ │ │ └── lt-spanned-row-test.js
│ │ └── helpers/
│ │ ├── compute-test.js
│ │ └── html-safe-test.js
│ ├── test-helper.js
│ └── unit/
│ ├── .gitkeep
│ ├── classes/
│ │ ├── column-test.js
│ │ ├── row-test.js
│ │ └── table-test.js
│ └── mixins/
│ └── table-header-test.js
└── yuidoc.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
indent_style = space
indent_size = 2
[*.hbs]
insert_final_newline = false
[*.{diff,md}]
trim_trailing_whitespace = false
================================================
FILE: .ember-cli
================================================
{
/**
Ember CLI sends analytics information by default. The data is completely
anonymous, but there are times when you might want to disable this behavior.
Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": false,
/**
Setting `isTypeScriptProject` to true will force the blueprint generators to generate TypeScript
rather than JavaScript by default, when a TypeScript version of a given blueprint is available.
*/
"isTypeScriptProject": false
}
================================================
FILE: .eslintignore
================================================
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/coverage/
!.*
.*/
.eslintcache
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/npm-shrinkwrap.json.ember-try
/package.json.ember-try
/package-lock.json.ember-try
/yarn.lock.ember-try
================================================
FILE: .eslintrc.js
================================================
'use strict';
module.exports = {
root: true,
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true,
},
},
plugins: ['ember'],
extends: [
'eslint:recommended',
'plugin:ember/recommended',
'plugin:prettier/recommended',
],
env: {
browser: true,
},
rules: {
// TODO: enable all these rules and fix the violations
'ember/classic-decorator-no-classic-methods': 'off',
'ember/classic-decorator-hooks': 'off',
'ember/no-actions-hash': 'off',
'ember/no-classic-classes': 'off',
'ember/no-classic-components': 'off',
'ember/no-component-lifecycle-hooks': 'off',
'ember/no-computed-properties-in-native-classes': 'off',
'ember/no-observers': 'off',
'ember/no-jquery': 'error',
'ember/no-get': 'warn',
'ember/no-mixins': 'off',
'ember/no-new-mixins': 'off',
'ember/require-tagless-components': 'off',
},
overrides: [
// node files
{
files: [
'./.eslintrc.js',
'./.prettierrc.js',
'./.template-lintrc.js',
'./ember-cli-build.js',
'./index.js',
'./testem.js',
'./blueprints/*/index.js',
'./config/**/*.js',
'./tests/dummy/config/**/*.js',
],
parserOptions: {
sourceType: 'script',
},
env: {
browser: false,
node: true,
},
plugins: ['node'],
extends: ['plugin:node/recommended'],
},
{
// test files
files: ['tests/**/*-test.{js,ts}'],
extends: ['plugin:qunit/recommended'],
rules: {
'qunit/require-expect': 'off',
},
},
],
};
================================================
FILE: .github/workflows/ci.yml
================================================
name: CI
on:
push:
branches:
- main
- master
pull_request: {}
concurrency:
group: ci-${{ github.head_ref || github.ref }}
cancel-in-progress: true
jobs:
test:
name: "Tests"
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 14.x
cache: yarn
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Lint
run: yarn lint
- name: Run Tests
run: yarn test:ember
floating:
name: "Floating Dependencies"
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 14.x
cache: yarn
- name: Install Dependencies
run: yarn install --no-lockfile
- name: Run Tests
run: yarn test:ember
try-scenarios:
name: ${{ matrix.try-scenario }}
runs-on: ubuntu-latest
needs: "test"
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
try-scenario:
- ember-lts-3.24
- ember-lts-3.28
- ember-lts-4.4
- ember-release
- ember-beta
- ember-canary
- ember-default-with-jquery
- ember-classic
- embroider-safe
# - embroider-optimized
steps:
- uses: actions/checkout@v3
- name: Install Node
uses: actions/setup-node@v3
with:
node-version: 14.x
cache: yarn
- name: Install Dependencies
run: yarn install --frozen-lockfile
- name: Run Tests
run: ./node_modules/.bin/ember try:one ${{ matrix.try-scenario }}
================================================
FILE: .gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/.env*
/.pnp*
/.sass-cache
/.eslintcache
/connect.lock
/coverage/
/libpeerconnection.log
/npm-debug.log*
/testem.log
/yarn-error.log
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/npm-shrinkwrap.json.ember-try
/package.json.ember-try
/package-lock.json.ember-try
/yarn.lock.ember-try
# broccoli-debug
/DEBUG/
# VS Code
.vscodeignore
jsconfig.json
/typings/*
/.vscode/*
# other stuff
lcov.dat
================================================
FILE: .npmignore
================================================
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
# misc
/.bowerrc
/.editorconfig
/.ember-cli
/.env*
/.eslintcache
/.eslintignore
/.eslintrc.js
/.git/
/.github/
/.gitignore
/.prettierignore
/.prettierrc.js
/.template-lintrc.js
/.travis.yml
/.watchmanconfig
/bower.json
/CONTRIBUTING.md
/ember-cli-build.js
/testem.js
/tests/
/yarn-error.log
/yarn.lock
.gitkeep
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/npm-shrinkwrap.json.ember-try
/package.json.ember-try
/package-lock.json.ember-try
/yarn.lock.ember-try
================================================
FILE: .prettierignore
================================================
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/coverage/
!.*
.eslintcache
.lint-todo/
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/npm-shrinkwrap.json.ember-try
/package.json.ember-try
/package-lock.json.ember-try
/yarn.lock.ember-try
================================================
FILE: .prettierrc.js
================================================
'use strict';
module.exports = {
singleQuote: true,
overrides: [
{
files: '**/*.hbs',
options: {
parser: 'glimmer',
singleQuote: false,
},
},
],
};
================================================
FILE: .template-lintrc.js
================================================
'use strict';
module.exports = {
extends: 'recommended',
rules: {
'no-action': false,
'no-curly-component-invocation': false,
'no-down-event-binding': false,
'no-duplicate-landmark-elements': false,
'no-heading-inside-button': false,
'no-inline-styles': false,
'no-nested-landmark': false,
'no-passed-in-event-handlers': false,
'no-yield-only': false,
'require-context-role': false,
'require-input-label': false,
'require-presentational-children': false,
},
};
================================================
FILE: .tool-versions
================================================
nodejs 14.20.0
================================================
FILE: .watchmanconfig
================================================
{
"ignore_dirs": ["tmp", "dist"]
}
================================================
FILE: CHANGELOG.md
================================================
Changelog
=========
## v3.0.0-beta.2 (2023-01-17)
#### :boom: Breaking Change
* [#809](https://github.com/adopted-ember-addons/ember-light-table/pull/809) Convert positional params to named params ([@maxwondercorn](https://github.com/maxwondercorn))
* [#807](https://github.com/adopted-ember-addons/ember-light-table/pull/807) Create local html-safe helper/remove ember-cli-string-helpers ([@maxwondercorn](https://github.com/maxwondercorn))
#### :bug: Bug Fix
* [#825](https://github.com/adopted-ember-addons/ember-light-table/pull/825) Fix: Add ...attributes to lt-body ([@IgnaceMaes](https://github.com/IgnaceMaes))
* [#824](https://github.com/adopted-ember-addons/ember-light-table/pull/824) FIx deprecation for using this.attrs for arguments in template ([@vstefanovic97](https://github.com/vstefanovic97))
#### :house: Internal
* [#815](https://github.com/adopted-ember-addons/ember-light-table/pull/815) Update examples ([@rwwagner90](https://github.com/rwwagner90))
#### Committers: 4
- Gregg Martell ([@maxwondercorn](https://github.com/maxwondercorn))
- Ignace Maes ([@IgnaceMaes](https://github.com/IgnaceMaes))
- Robert Wagner ([@rwwagner90](https://github.com/rwwagner90))
- Vuk ([@vstefanovic97](https://github.com/vstefanovic97))
## v3.0.0-beta.1 (2022-07-21)
#### :boom: Breaking Change
* [#805](https://github.com/adopted-ember-addons/ember-light-table/pull/805) Make light-table tagless ([@rwwagner90](https://github.com/rwwagner90))
* [#804](https://github.com/adopted-ember-addons/ember-light-table/pull/804) Remove enableSync option, require updating table rows manually ([@rwwagner90](https://github.com/rwwagner90))
* [#757](https://github.com/adopted-ember-addons/ember-light-table/pull/757) Bump deps, update GitHub actions ([@rwwagner90](https://github.com/rwwagner90))
* [#784](https://github.com/adopted-ember-addons/ember-light-table/pull/784) Remove fix-proto - Drop support for IE < 10 ([@maxwondercorn](https://github.com/maxwondercorn))
* [#780](https://github.com/adopted-ember-addons/ember-light-table/pull/780) Drop node 10 ([@maxwondercorn](https://github.com/maxwondercorn))
* [#775](https://github.com/adopted-ember-addons/ember-light-table/pull/775) Merge post 2.0.0-beta.5 branches ([@maxwondercorn](https://github.com/maxwondercorn))
* [#755](https://github.com/adopted-ember-addons/ember-light-table/pull/755) Merge 3-x into master ([@rwwagner90](https://github.com/rwwagner90))
#### :rocket: Enhancement
* [#601](https://github.com/adopted-ember-addons/ember-light-table/pull/601) Avoid breaking line with sort icon in narrow columns ([@Gorzas](https://github.com/Gorzas))
* [#648](https://github.com/adopted-ember-addons/ember-light-table/pull/648) Expose shouldRecycle property of vertical-collection ([@Gaurav0](https://github.com/Gaurav0))
* [#584](https://github.com/adopted-ember-addons/ember-light-table/pull/584) Improve cells performance ([@mostafa-sakhiri](https://github.com/mostafa-sakhiri))
#### :bug: Bug Fix
* [#803](https://github.com/adopted-ember-addons/ember-light-table/pull/803) Fix scroll to row ([@rwwagner90](https://github.com/rwwagner90))
* [#800](https://github.com/adopted-ember-addons/ember-light-table/pull/800) Fix responsive functionality ([@rwwagner90](https://github.com/rwwagner90))
* [#798](https://github.com/adopted-ember-addons/ember-light-table/pull/798) Fix onScrolledToBottom / use render modifiers ([@rwwagner90](https://github.com/rwwagner90))
* [#790](https://github.com/adopted-ember-addons/ember-light-table/pull/790) Import computed macros directly ([@rwwagner90](https://github.com/rwwagner90))
* [#681](https://github.com/adopted-ember-addons/ember-light-table/pull/681) use `assign` instead of `merge` ([@bekzod](https://github.com/bekzod))
* [#664](https://github.com/adopted-ember-addons/ember-light-table/pull/664) Fixing issue with multiple tables and onScrolledToBottom. ([@gmurphey](https://github.com/gmurphey))
* [#666](https://github.com/adopted-ember-addons/ember-light-table/pull/666) Pinning ip-regex to fix build issue. ([@gmurphey](https://github.com/gmurphey))
* [#596](https://github.com/adopted-ember-addons/ember-light-table/pull/596) [Draggable Column] Error when dragging column; "removeObject is not a function" ([@msenevir](https://github.com/msenevir))
* [#586](https://github.com/adopted-ember-addons/ember-light-table/pull/586) FIX - Incomplete use of htmlSafe() on Cell.style ([@ghost](https://github.com/ghost))
#### :house: Internal
* [#806](https://github.com/adopted-ember-addons/ember-light-table/pull/806) Convert dummy app to glimmer components ([@rwwagner90](https://github.com/rwwagner90))
* [#801](https://github.com/adopted-ember-addons/ember-light-table/pull/801) Make embroider-safe ([@rwwagner90](https://github.com/rwwagner90))
* [#799](https://github.com/adopted-ember-addons/ember-light-table/pull/799) Tweak some icons ([@rwwagner90](https://github.com/rwwagner90))
* [#797](https://github.com/adopted-ember-addons/ember-light-table/pull/797) Minor icon fixes ([@maxwondercorn](https://github.com/maxwondercorn))
* [#796](https://github.com/adopted-ember-addons/ember-light-table/pull/796) Fix font-awesome icons, fix some build issues ([@rwwagner90](https://github.com/rwwagner90))
* [#793](https://github.com/adopted-ember-addons/ember-light-table/pull/793) Convert dummy app ([@maxwondercorn](https://github.com/maxwondercorn))
* [#792](https://github.com/adopted-ember-addons/ember-light-table/pull/792) Update ember-scrollable ([@rwwagner90](https://github.com/rwwagner90))
* [#791](https://github.com/adopted-ember-addons/ember-light-table/pull/791) Fix implicit `this`, runloop, and assign issues ([@rwwagner90](https://github.com/rwwagner90))
* [#779](https://github.com/adopted-ember-addons/ember-light-table/pull/779) Remove Bower configuration ([@maxwondercorn](https://github.com/maxwondercorn))
* [#653](https://github.com/adopted-ember-addons/ember-light-table/pull/653) Fix scroll to bottom test ([@Gaurav0](https://github.com/Gaurav0))
* [#649](https://github.com/adopted-ember-addons/ember-light-table/pull/649) Write integration tests for occlusion rendering ([@Gaurav0](https://github.com/Gaurav0))
* [#598](https://github.com/adopted-ember-addons/ember-light-table/pull/598) Stop using nativeDomClick which is deprecated. ([@plcarmel](https://github.com/plcarmel))
#### Committers: 11
- Chris Thoburn ([@runspired](https://github.com/runspired))
- Deleted user ([@ghost](https://github.com/ghost))
- Garrett Murphey ([@gmurphey](https://github.com/gmurphey))
- Gaurav Munjal ([@Gaurav0](https://github.com/Gaurav0))
- José David Cano Pérez ([@Gorzas](https://github.com/Gorzas))
- Mahen Seneviratne ([@msenevir](https://github.com/msenevir))
- Pierre-Luc Carmel Biron ([@plcarmel](https://github.com/plcarmel))
- Robert Wagner ([@rwwagner90](https://github.com/rwwagner90))
- [@bekzod](https://github.com/bekzod)
- [@mostafa-sakhiri](https://github.com/mostafa-sakhiri)
- maxwondercorn ([@maxwondercorn](https://github.com/maxwondercorn))
## UNRELEASED 2.X
#### Bug Fixes
* [#734](https://github.com/offirgolan/ember-light-table/pull/734) bump dependency addons ([@fran-worley](https://github.com/fran-worley))
#### Internal
* [#733](https://github.com/offirgolan/ember-light-table/pull/733) Bump Ember CLI to v3.16 (LTS) + bump core addons to latest ([@fran-worley](https://github.com/fran-worley))
#### Committers: 1
- Fran Worley ([@fran-worley](https://github.com/fran-worley))
## v2.0.0-beta.5 (2020-01-16)
#### :boom: Breaking Change
* [#718](https://github.com/offirgolan/ember-light-table/pull/718) Replace volatile computed properties ([@fran-worley](https://github.com/fran-worley))
#### Bug Fixes
* [#722](https://github.com/offirgolan/ember-light-table/pull/722) Fix resizing columns issues(2.x) ([@TomaszWegrzyn](https://github.com/TomaszWegrzyn))
* [#718](https://github.com/offirgolan/ember-light-table/pull/718) Replace volatile computed properties ([@fran-worley](https://github.com/fran-worley))
#### Enhancements
* [8d0b592](https://github.com/offirgolan/ember-light-table/commit/8d0b592938ddaecc6d7353eaefab749bcc77175f) Update ember-scrollable version to jquery-less ([@alexander-alvarez](https://github.com/alexander-alvarez))
#### Committers: 3
- Alexander Alvarez ([@alexander-alvarez](https://github.com/alexander-alvarez))
- Tomasz Wegrzyn [@TomaszWegrzyn](https://github.com/TomaszWegrzyn)
- Fran Worley ([@fran-worley](https://github.com/fran-worley))
## v2.0.0-beta.4 (2019-08-19)
#### :boom: Breaking Change
* [#701](https://github.com/offirgolan/ember-light-table/pull/701) Convert ES6 native classes to ember objects ([@fran-worley](https://github.com/fran-worley))
* [#713](https://github.com/offirgolan/ember-light-table/pull/713) Set minimum supported ember version at 3.4 ([@fran-worley](https://github.com/fran-worley))
* [#698](https://github.com/offirgolan/ember-light-table/pull/698) Drop support for Node 6 as end of life 30 April 2019 ([@fran-worley](https://github.com/fran-worley))
#### Bug Fixes
* [#701](https://github.com/offirgolan/ember-light-table/pull/701) Convert ES6 native classes to ember objects ([@fran-worley](https://github.com/fran-worley))
* [#693](https://github.com/offirgolan/ember-light-table/pull/693) Update ember-in-viewport, ember-wormhole ([@fran-worley](https://github.com/fran-worley))
* [#692](https://github.com/offirgolan/ember-light-table/pull/692) Replace propertyWillChange/propertyDidChange with notifyPropertyChange ([@mmadsen2](https://github.com/mmadsen2))
* [#681](https://github.com/offirgolan/ember-light-table/pull/681) use `assign` instead of `merge` ([@bekzod](https://github.com/bekzod))
* [#664](https://github.com/offirgolan/ember-light-table/pull/664) Fixing issue with multiple tables and onScrolledToBottom. ([@gmurphey](https://github.com/gmurphey))
* [#666](https://github.com/offirgolan/ember-light-table/pull/666) Pinning ip-regex to fix build issue. ([@gmurphey](https://github.com/gmurphey))
* [#596](https://github.com/offirgolan/ember-light-table/pull/596) [Draggable Column] Error when dragging column; "removeObject is not a function" ([@msenevir](https://github.com/msenevir))
#### Internal
* [#716](https://github.com/offirgolan/ember-light-table/pull/716) Bump to ember cli 3.12 and update dependencies ([@fran-worley](https://github.com/fran-worley))
* [#697](https://github.com/offirgolan/ember-light-table/pull/697) Migrate from ember-cli-changelog to lerna-changelog ([@fran-worley](https://github.com/fran-worley))
* [#696](https://github.com/offirgolan/ember-light-table/pull/696) Bump Ember CLI to 3.8 and update other dependencies ([@fran-worley](https://github.com/fran-worley))
* [#693](https://github.com/offirgolan/ember-light-table/pull/693) Update ember-in-viewport, ember-wormhole ([@fran-worley](https://github.com/fran-worley))
#### Committers: 5
- mmadsen2 [@mmadsen2](https://github.com/mmadsen2)
- bek ([@bekzod](https://github.com/bekzod))
- Garrett Murphey ([@gmurphey](https://github.com/gmurphey))
- Mahen Seneviratne ([@msenevir](https://github.com/msenevir))
- Fran Worley ([@fran-worley](https://github.com/fran-worley))
## v2.0.0-beta.3 (2019-05-9)
#### Breaking
- [#657](https://github.com/offirgolan/ember-light-table/pull/657) Officially drop support for node 4 ([@Gaurav0](https://github.com/Gaurav0))
#### Enhancements
* [#601](https://github.com/offirgolan/ember-light-table/pull/601) Avoid breaking line with sort icon in narrow columns ([@Goras](https://github.com/Gorzas))
* [#648](https://github.com/offirgolan/ember-light-table/pull/648) Expose shouldRecycle property of vertical-collection ([@Gaurav0](https://github.com/Gaurav0))
#### Bug Fixes
* [#672](https://github.com/offirgolan/ember-light-table/pull/672) bump vertical-collection to v1.0.0-beta.13 ([@fran-worley](https://github.com/fran-worley))
* [#686](https://github.com/offirgolan/ember-light-table/pull/686) refactor: Remove sendAction() calls ([@MichalBryxi](https://github.com/MichalBryxi))
* [#673](https://github.com/offirgolan/ember-light-table/pull/673) Replace merge with assign ([@fran-worley](https://github.com/fran-worley))
* [#677](https://github.com/offirgolan/ember-light-table/pull/677) ensure ember-scrollable updates when rows are updated ([@fran-worley](https://github.com/fran-worley))
#### Internal
* [#598](https://github.com/offirgolan/ember-light-table/pull/598) Stop using nativeDomClick which is deprecated. ([@plcarmel](https://github.com/plcarmel))
* [#649](https://github.com/offirgolan/ember-light-table/pull/649) Write integration tests for occlusion rendering ([@Gaurav0](https://github.com/Gaurav0))
* [#651](https://github.com/offirgolan/ember-light-table/pull/651) Update ember-cli-changelog ([@Gaurav0](https://github.com/Gaurav0))
* [#653](https://github.com/offirgolan/ember-light-table/pull/653) Fix scroll to bottom test ([@Gaurav0](https://github.com/Gaurav0))
* [#655](https://github.com/offirgolan/ember-light-table/pull/655) Update ember-scrollable ([@Gaurav0](https://github.com/Gaurav0))
* [#656](https://github.com/offirgolan/ember-light-table/pull/656) Assert and Test compatibility with LTS 3.4 ([@Gaurav0](https://github.com/Gaurav0))
#### Committers: 4
- Pierre-Luc Carmel Biron ([@plcarmel](https://github.com/plcarmel))
- Gaurav Munjal ([@Gaurav0](https://github.com/Gaurav0))
- Fran Worley ([@fran-worley](https://github.com/fran-worley))
- Michal Bryxi ([@MichalBryxi](https://github.com/MichalBryxi))
## v2.0.0-beta.2 (2018-10-29)
#### Enhancements
*[#593](https://github.com/offirgolan/ember-light-table/pull/593) Remove jQuery usage ((@donaldwasserman)[https://github.com/donaldwasserman])
#### Committers: 1
- Donald Wasserman ((@donaldwasserman)[https://github.com/donaldwasserman])
## v2.0.0-beta.1 (2018-10-26)
#### Bug Fixes
*[#590](https://github.com/offirgolan/ember-light-table/pull/590) replace `sendAction` with modern callable methods ((@donaldwasserman)[https://github.com/donaldwasserman])
#### Committers: 1
- Donald Wasserman ((@donaldwasserman)[https://github.com/donaldwasserman])
## v2.0.0-beta.0 (2018-10-25)
#### Enhancements
* [#584](https://github.com/offirgolan/ember-light-table/pull/584) Improve cells performance ([@mostafa-sakhiri](https://github.com/mostafa-sakhiri))
#### Bug Fixes
* [#586](https://github.com/offirgolan/ember-light-table/pull/586) Incomplete use of htmlSafe() on Cell.style. ([@richard-viney](https://github.com/richard-viney))
#### Committers: 2
- mostafa-sakhiri ([@mostafa-sakhiri](https://github.com/mostafa-sakhiri))
- Richard Viney ([@richard-viney](https://github.com/richard-viney))
## UNRELEASED MASTER
#### Enhancements
* [#584](https://github.com/offirgolan/ember-light-table/pull/584) Improve cells performance ([@mostafa-sakhiri](https://github.com/mostafa-sakhiri))
* [#601](https://github.com/offirgolan/ember-light-table/pull/601) Avoid breaking line with sort icon in narrow columns ([@Goras](https://github.com/Gorzas))
* [#648](https://github.com/offirgolan/ember-light-table/pull/648) Expose shouldRecycle property of vertical-collection ([@Gaurav0](https://github.com/Gaurav0))
#### Bug Fixes
* [#692](https://github.com/offirgolan/ember-light-table/pull/692) Replace propertyWillChange/propertyDidChange with notifyPropertyChange ([@mmadsen2](https://github.com/mmadsen2))
* [#681](https://github.com/offirgolan/ember-light-table/pull/681) use `assign` instead of `merge` ([@bekzod](https://github.com/bekzod))
* [#664](https://github.com/offirgolan/ember-light-table/pull/664) Fixing issue with multiple tables and onScrolledToBottom. ([@gmurphey](https://github.com/gmurphey))
* [#666](https://github.com/offirgolan/ember-light-table/pull/666) Pinning ip-regex to fix build issue. ([@gmurphey](https://github.com/gmurphey))
* [#596](https://github.com/offirgolan/ember-light-table/pull/596) [Draggable Column] Error when dragging column; "removeObject is not a function" ([@msenevir](https://github.com/msenevir))
* [#586](https://github.com/offirgolan/ember-light-table/pull/586) Incomplete use of htmlSafe() on Cell.style. ([@richard-viney](https://github.com/richard-viney))
#### Internal
* [#598](https://github.com/offirgolan/ember-light-table/pull/598) Stop using nativeDomClick which is deprecated. ([@plcarmel](https://github.com/plcarmel))
- [#649](https://github.com/offirgolan/ember-light-table/pull/649) Write integration tests for occlusion rendering ([@Gaurav0](https://github.com/Gaurav0))
- [#653](https://github.com/offirgolan/ember-light-table/pull/653) Fix scroll to bottom test ([@Gaurav0](https://github.com/Gaurav0))
- [#651](https://github.com/offirgolan/ember-light-table/pull/651) Update ember-cli-changelog ([@Gaurav0](https://github.com/Gaurav0))
#### Committers: 8
- Garrett Murphey ([@gmurphey](https://github.com/gmurphey))
- Mahen Seneviratne ([@msenevir](https://github.com/msenevir))
- mmadsen2 [@mmadsen2](https://github.com/mmadsen2)
- bek ([@bekzod](https://github.com/bekzod))
- José David Cano Pérez ([@Goras](https://github.com/Gorzas))
- Gaurav Munjal ([@Gaurav0](https://github.com/Gaurav0))
- mostafa-sakhiri ([@mostafa-sakhiri](https://github.com/mostafa-sakhiri))
- Richard Viney ([@richard-viney](https://github.com/richard-viney))
- Pierre-Luc Carmel Biron ([@plcarmel](https://github.com/plcarmel))
## v1.13.2 (2018-08-26)
#### Bug Fixes
- [e345fec](https://github.com/offirgolan/ember-light-table/commit/e345fec67916fc18ced40cd161dbf38de934e894) Use isArray to check columns, rows type ([@quaertym](https://github.com/quaertym))
#### Internal
- [7b50190](https://github.com/offirgolan/ember-light-table/commit/7b5019003b01ad4bb646d1f142ab63059bf4efd4) Update other dependencies ([@alexander-alvarez](https://github.com/alexander-alvarez))
- [715d94b](https://github.com/offirgolan/ember-light-table/commit/715d94b47cd5cbe31af99db8d6faf8aa7c00f124) Update Ember scrollable ([@Gaurav0](https://github.com/Gaurav0))
#### Committers: 3
- Emre Unal ([@quaertym](https://github.com/quaertym)
- Alex Alvarez ([@alexander-alvarez](https://github.com/alexander-alvarez))
- Gaurav Munjal ([@Gaurav0](https://github.com/Gaurav0))
## v1.13.1 (2018-06-22)
#### Internal
- [ace7f4c](https://github.com/offirgolan/ember-light-table/commit/ace7f4cc3535853fb07c406d5e3a06467d6a7f0d) Update ember-cli to 3.1.4 ([@jrjohnson](https://github.com/jrjohnson))
- [bf6edb8](https://github.com/offirgolan/ember-light-table/commit/bf6edb83fdc7fa195c786b7b1aa1826edde4518a) Update all dependencies ([@jrjohnson](https://github.com/jrjohnson))
#### Committers: 1
- Jonathan Johnson ([@jrjohnson](https://github.com/jrjohnson))
## v1.13.0 (2018-06-21)
#### Commits
- [5dccab6a](https://github.com/offirgolan/ember-light-table/commit/5dccab6a47644eef0381b30004802aa88958f176) **test(light-table/onScrolledToBottom)**: skip *by [Jan Buschtöns](https://github.com/buschtoens)*
- [a3af0b48](https://github.com/offirgolan/ember-light-table/commit/a3af0b483e1bdf354031832faf72acbf1cbbdb31) **test(lt-body/scaffolding)**: use querySelectorAll for subquery *by [Jan Buschtöns](https://github.com/buschtoens)*
- [07972532](https://github.com/offirgolan/ember-light-table/commit/079725321d7a540c58e970815a757fe4298f4cd2) **fix(lt-infinity)**: disable intersection observer *by [Jan Buschtöns](https://github.com/buschtoens)*
- [59054009](https://github.com/offirgolan/ember-light-table/commit/59054009cce1eed818926eb34c1447a4fd0cdd82) **fix(classes/{Column,Row})**: assign properties in the Ember init hook *by [Jan Buschtöns](https://github.com/buschtoens)*
- [2cc88bac](https://github.com/offirgolan/ember-light-table/commit/2cc88bacf8389ff59b2680205f9bff50fd0ab15c) **fix(lt-infinity)**: set default scroll buffer to 0 *by [Jan Buschtöns](https://github.com/buschtoens)*
- [35c89933](https://github.com/offirgolan/ember-light-table/commit/35c8993315aba2730c3cbeaa6b3e3b3a2ad445f0) **refactor(mixins/table-header)**: set sharedOptions.fixed(Header|Footer) once in init *by [Jan Buschtöns](https://github.com/buschtoens)*
- [5a4fd499](https://github.com/offirgolan/ember-light-table/commit/5a4fd499195884235cde9924715ad59c0f74ffea) **docs(README)**: fix Ember.js versions badge *by [Jan Buschtöns](https://github.com/buschtoens)*
- [fa9e50b8](https://github.com/offirgolan/ember-light-table/commit/fa9e50b89ff00f652d77177e254326f1fce496e4) **docs(README)**: add logo *by [Jan Buschtöns](https://github.com/buschtoens)*
- [0d99b0f4](https://github.com/offirgolan/ember-light-table/commit/0d99b0f4655d6a02d0ee1d3c1801db822922269d) **fix(Table)**: constructor asserts param types (#522) *by [Redmond Tran](https://github.com/RedTn)*
- [f5b56c97](https://github.com/offirgolan/ember-light-table/commit/f5b56c9710d6947e66f396ff511a67d57a1edf95) **fix(draggable-column)**: guard against undefined sourceColumn (#521) *by [Craig MacKenzie](https://github.com/cmackenz)*
## v1.12.2
#### Commits
- [6d71609d](https://github.com/offirgolan/ember-light-table/commit/6d71609da875453ff9792f636b88c5c2e7e7f385) **fix(occlusion)**: wire up lastVisibleChanged *by [Jan Buschtöns](https://github.com/buschtoens)*
## v1.12.1
This patch release primarily re-enabled dynamic column sizing for occlusion tables and wires up the `onScrolledToBottom` and `onScroll` actions.
However, we have to (temporarily) remove expanded rows. See [this comment in #514]( https://github.com/offirgolan/ember-light-table/pull/514#issuecomment-346613745) for more details.
#### Commits
- [55f5962e](https://github.com/offirgolan/ember-light-table/commit/55f5962e934b2c003e29812bc9ec76be18bbce7e) **fix(occlusion)**: remove colspan from loader and no-data spanned rows *by [Jan Buschtöns](https://github.com/buschtoens)*
- [5f6637e3](https://github.com/offirgolan/ember-light-table/commit/5f6637e33445b0b73cc572f902661d5c98559757) **fix(occlusion)**: temporarily remove yield inside vertical-collection *by [Jan Buschtöns](https://github.com/buschtoens)*
- [ee30bb83](https://github.com/offirgolan/ember-light-table/commit/ee30bb83ddad3f7e4c62dba60f1f33605f494199) **fix(occlusion)**: wire up onScroll and onScrolledToBottom *by [Jan Buschtöns](https://github.com/buschtoens)*
- [b93f0671](https://github.com/offirgolan/ember-light-table/commit/b93f0671ad635bf4024aaab1f7773db52df45cc7) **fix(occlusion)**: pass bufferSize based on scrollBuffer *by [Jan Buschtöns](https://github.com/buschtoens)*
- [c240a23c](https://github.com/offirgolan/ember-light-table/commit/c240a23c837d750c41511f93c190976e1d40d588) **fix(occlusion)**: tbody sizing via flexbox, dynamic column widths *by [Jan Buschtöns](https://github.com/buschtoens)*
- [140ea0d6](https://github.com/offirgolan/ember-light-table/commit/140ea0d60058136de6ad632aaf8b38b2c292b1c7) **docs(README)**: update "help wanted" label link *by [Jan Buschtöns](https://github.com/buschtoens)*
## v1.12.0
#### Commits
- [7feb748c](https://github.com/offirgolan/ember-light-table/commit/7feb748c670f31975156de2abca59958266daddf) **feat(lt-body)**: Preliminary Vertical collection integration (#483) *by [Alex Alvarez](https://github.com/alexander-alvarez)*
## v1.11.0
#### Commits
- [e16af170](https://github.com/offirgolan/ember-light-table/commit/e16af170a67492d4644ff113836706f0595387cc) **feat(table-header)**: custom icon components (#489) *by [RedTn](https://github.com/RedTn)*
- [daa657ee](https://github.com/offirgolan/ember-light-table/commit/daa657eea93414bbe2f9c34dfb99cd741a0d30f3) **fix(draggable-column)**: ensure the drop target remains properly identified (#496) *by [akshay-kr](https://github.com/akshay-kr)*
- [2e2faf93](https://github.com/offirgolan/ember-light-table/commit/2e2faf93a0d7979fa8e74de85c0eea18addc9564) **fix(draggable-column)**: ensure the drop target remains properly identified (#418) *by [RustyToms](https://github.com/RustyToms)*
## v1.10.0
### Pull Requests
- [#445](https://github.com/offirgolan/ember-light-table/pull/445) **readme**: add link to #e-light-table Slack channel *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#449](https://github.com/offirgolan/ember-light-table/pull/449) **head & foot**: make `table.height` optional, warn in `table-header` mixin *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#451](https://github.com/offirgolan/ember-light-table/pull/451) **table**: add `setRowsSynced` method *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#457](https://github.com/offirgolan/ember-light-table/pull/457) **light-table**: add `extra` property *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#464](https://github.com/offirgolan/ember-light-table/pull/464) **light-table**: add `iconSortable` property *by [Vince Eberle](https://github.com/ignatius-j)*
- [#473](https://github.com/offirgolan/ember-light-table/pull/473) **refactor**: migrate to RFC 176 style ES6 module imports *by [Robert Wagner](https://github.com/rwwagner90)*
- [#462](https://github.com/offirgolan/ember-light-table/pull/462) **ci/travis**: use headless Chrome *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#466](https://github.com/offirgolan/ember-light-table/pull/466) **ci**: align Chrome headless usage with ember-cli 2.15 *by [Jan Buschtöns](https://github.com/buschtoens)*
#### Commits
- [a60647ab](https://github.com/offirgolan/ember-light-table/commit/a60647abb87904e031afc90d5a083a5496da53fa) **test(light-table)**: add case for `extra` and `tableActions` *by [Jan Buschtöns](https://github.com/buschtoens)*
## v1.9.0
### Pull Requests
- [#390](https://github.com/offirgolan/ember-light-table/pull/390) Move ember-truth-helpers to dependencies *by [fsmanuel/chore](https://github.com/fsmanuel/chore)*
- [#422](https://github.com/offirgolan/ember-light-table/pull/422) Fix missing 'as body' on example code *by [Ahmad Suhendri](https://github.com/ahmadsoe)*
- [#438](https://github.com/offirgolan/ember-light-table/pull/438) Modernize ELT, kill bower and enable yarn *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#440](https://github.com/offirgolan/ember-light-table/pull/440) **tests/table**: isEmpty & isEmpty (enableSync = true) *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#441](https://github.com/offirgolan/ember-light-table/pull/441) **readme**: add more information on collaborating *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#439](https://github.com/offirgolan/ember-light-table/pull/439) Polyfill support for __proto__ in IE <= 10 *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#421](https://github.com/offirgolan/ember-light-table/pull/421) **lt-body**: add enableScaffolding option *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#445](https://github.com/offirgolan/ember-light-table/pull/445) **readme**: add link to #e-light-table Slack channel *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#449](https://github.com/offirgolan/ember-light-table/pull/449) **head & foot**: make `table.height` optional, warn in `table-header` mixin *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#451](https://github.com/offirgolan/ember-light-table/pull/451) **table**: add `setRowsSynced` method *by [Jan Buschtöns](https://github.com/buschtoens)*
#### Commits
- [b0db5b15](https://github.com/offirgolan/ember-light-table/commit/b0db5b15d96e1b7bfd8f96a3001bfac6338ec0b3) **update ember-scrollable version (#408)**: //github.com/offirgolan/ember-light-table/issues/396 *by [Rusty Toms](https://github.com/RustyToms)*
## v1.8.6
### Pull Requests
- [#385](https://github.com/offirgolan/ember-light-table/pull/385) Fixes 'onScroll' deprecation *by [Alex Alvarez](https://github.com/alexander-alvarez)*
- [#386](https://github.com/offirgolan/ember-light-table/pull/386) Move ember-cli-string-helpers to dependencies *by [Jonathan Steele](https://github.com/ynnoj)*
## v1.8.5
### Pull Requests
- [#383](https://github.com/offirgolan/ember-light-table/pull/383) Fix for ember-composable-helpers addon incompatibility *by [Nicholas McClay](https://github.com/nmcclay)*
## v1.8.4
### Pull Requests
- [#348](https://github.com/offirgolan/ember-light-table/pull/348) Update Column.js to support parent *by [Alex Alvarez](https://github.com/alexander-alvarez)*
## v1.8.3
### Pull Requests
- [#322](https://github.com/offirgolan/ember-light-table/pull/322) Fix typo for default colspan *by [Ilya Radchenko](https://github.com/knownasilya)*
- [#318](https://github.com/offirgolan/ember-light-table/pull/318) Change <span> to <i> tag for sorting icons *by [Julie Graceffa](https://github.com/jewls618)*
- [#332](https://github.com/offirgolan/ember-light-table/pull/332) Bump ember-scrollable *by [Offir Golan](https://github.com/offirgolan)*
#### Commits
- [70320d05](https://github.com/offirgolan/ember-light-table/commit/70320d05a99021e35d5c0878dccf6499ce88216c) **fix(package)**: update ember-get-config to version 0.2.1 *by [greenkeeper[bot]](https://github.com/greenkeeper[bot])*
## v1.8.2
### Pull Requests
- [#321](https://github.com/offirgolan/ember-light-table/pull/321) Update ember-scrollable to the latest version 🚀 *by [Offir Golan](https://github.com/offirgolan/greenkeeper)*
#### Commits
- [e2438a50](https://github.com/offirgolan/ember-light-table/commit/e2438a508e890ee7ccce7a02fde9654c047ebee8) **fix(package)**: update ember-scrollable to version 0.4.0 *by [greenkeeper[bot]](https://github.com/greenkeeper[bot])*
## v1.8.1
### Pull Requests
- [#303](https://github.com/offirgolan/ember-light-table/pull/303) Remove deprecated Ember.K *by [cibernox](https://github.com/cibernox)*
- [#308](https://github.com/offirgolan/ember-light-table/pull/308) Update ember-in-viewport to the latest version 🚀 *by [Offir Golan](https://github.com/offirgolan/greenkeeper)*
## v1.8.0
### Pull Requests
- [#290](https://github.com/offirgolan/ember-light-table/pull/290) [FEATURE] Add selectOnClick option *by [Offir Golan](https://github.com/offirgolan)*
## v1.7.1
### Pull Requests
- [#286](https://github.com/offirgolan/ember-light-table/pull/286) [BUGFIX] In viewport left/right tolerance adjustment *by [Offir Golan](https://github.com/offirgolan)*
## v1.7.0
### Pull Requests
- [#222](https://github.com/offirgolan/ember-light-table/pull/222) [FEATURE] Support horizontal scrolling *by [Offir Golan](https://github.com/offirgolan)*
- [#281](https://github.com/offirgolan/ember-light-table/pull/281) [BUGFIX] Resolve IE drag and drop crashes *by [Offir Golan](https://github.com/offirgolan)*
## v1.6.1
### Pull Requests
- [#266](https://github.com/offirgolan/ember-light-table/pull/266) [BUGFIX] Require ember-scrollable@^0.3.5 *by [Jan Buschtöns](https://github.com/buschtoens)*
## v1.6.0
### Pull Requests
- [#252](https://github.com/offirgolan/ember-light-table/pull/252) [BUGFIX] Resizable column improvements *by [Offir Golan](https://github.com/offirgolan)*
- [#254](https://github.com/offirgolan/ember-light-table/pull/254) [BUGFIX] repeated scrollToRow *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#258](https://github.com/offirgolan/ember-light-table/pull/258) [FEATURE] Draggable Columns *by [Offir Golan](https://github.com/offirgolan)*
## v1.5.2
### Pull Requests
- [#244](https://github.com/offirgolan/ember-light-table/pull/244) [FEATURE] minResizeWidth + Event bubbling fix *by [Offir Golan](https://github.com/offirgolan)*
## v1.5.1
### Pull Requests
- [#241](https://github.com/offirgolan/ember-light-table/pull/241) [BUGFIX] Add safe checks to scroll logic *by [Offir Golan](https://github.com/offirgolan)*
## v1.5.0
### Pull Requests
- [#221](https://github.com/offirgolan/ember-light-table/pull/221) [FEATURE] Add label to base column to be used in column types *by [Offir Golan](https://github.com/offirgolan)*
- [#228](https://github.com/offirgolan/ember-light-table/pull/228) [FEATURE] ScrollTo and ScrollToRow *by [Jan Buschtöns](https://github.com/buschtoens)*
- [#235](https://github.com/offirgolan/ember-light-table/pull/235) [FEATURE] Responsive Columns *by [Offir Golan](https://github.com/offirgolan)*
## v1.4.4
### Pull Requests
- [#220](https://github.com/offirgolan/ember-light-table/pull/220) [BUGFIX] CPs using filterBy should also be dependent on the array size *by [Offir Golan](https://github.com/offirgolan)*
## v1.4.3
### Pull Requests
- [#214](https://github.com/offirgolan/ember-light-table/pull/214) [BUGFIX] enableSync sorting duplicates records *by [Offir Golan](https://github.com/offirgolan)*
## v1.4.2
### Pull Requests
- [#211](https://github.com/offirgolan/ember-light-table/pull/211) Upgrade dependencies to support Ember 2.9.0 *by [Offir Golan](https://github.com/offirgolan)*
## v1.4.1
### Pull Requests
- [#204](https://github.com/offirgolan/ember-light-table/pull/204) Update ember-scrollable *by [Taras Mankovski](https://github.com/taras)*
## v1.4.0
### Pull Requests
- [#167](https://github.com/offirgolan/ember-light-table/pull/167) [FEATURE] Two-way sync between rows and model *by [Offir Golan](https://github.com/offirgolan)*
- [#177](https://github.com/offirgolan/ember-light-table/pull/177) [FEATURE] Customizable components *by [Taras Mankovski](https://github.com/taras)*
- [#183](https://github.com/offirgolan/ember-light-table/pull/183) [BUGFIX] Add footer scaffolding and move width into style attr *by [Offir Golan](https://github.com/offirgolan)*
## v1.3.1
### Pull Requests
- [#166](https://github.com/offirgolan/ember-light-table/pull/166) [FEATURE] Introduce `resizeOnDrag` for column resizing *by [Offir Golan](https://github.com/offirgolan)*
## v1.3.0
### Pull Requests
- [#164](https://github.com/offirgolan/ember-light-table/pull/164) [FEATURE] Rename flattenedColumns to allColumns *by [Offir Golan](https://github.com/offirgolan)*
## v1.2.0
### Pull Requests
- [#160](https://github.com/offirgolan/ember-light-table/pull/160) [FEATURE] `multiSelectRequiresKeyboard` option for toggling row selection without ctrl/cmd *by [Jeremy Bargar](https://github.com/bargar)*
- [#163](https://github.com/offirgolan/ember-light-table/pull/163) [BUGFIX] Autoprefix addon.css (until PostCSS is up and running) + install ember-cli-autoprefixer to prefix demo page CSS *by [Offir Golan](https://github.com/offirgolan)*
- [#163](https://github.com/offirgolan/ember-light-table/pull/163) [BUGFIX] Pass table instance + rawValue to custom cell component *by [Offir Golan](https://github.com/offirgolan)*
- [#163](https://github.com/offirgolan/ember-light-table/pull/163) [BUGFIX] Use style instead of deprecated width attribute *by [Offir Golan](https://github.com/offirgolan)*
- [#163](https://github.com/offirgolan/ember-light-table/pull/163) [BUGFIX] Remove readOnly from value in base cell so it can be modified *by [Offir Golan](https://github.com/offirgolan)*
- [#163](https://github.com/offirgolan/ember-light-table/pull/163) [BUGFIX] Column resizer now applies width to table rows on `mouseUp` instead of on `mouseMove` *by [Offir Golan](https://github.com/offirgolan)*
## v1.1.1
### Pull Requests
- [#133](https://github.com/offirgolan/ember-light-table/pull/133) [BUGFIX] onScrolledToBottom doesnt get re-triggered after removing table rows *by [Offir Golan](https://github.com/offirgolan)*
## v1.1.0
### Pull Requests
- [#98](https://github.com/offirgolan/ember-light-table/pull/98) [FEATURE] Resizable Columns *by [Offir Golan](https://github.com/offirgolan)*
- [#115](https://github.com/offirgolan/ember-light-table/pull/115) [FEATURE] Style Table Element *by [Offir Golan](https://github.com/offirgolan)*
- [#117](https://github.com/offirgolan/ember-light-table/pull/117) [BUGFIX] onScrolledToBottom doesnt get re-triggered when there arent enough rows in the table *by [Offir Golan](https://github.com/offirgolan)*
- [#122](https://github.com/offirgolan/ember-light-table/pull/122) [BUGFIX] Remove deprecations *by [Offir Golan](https://github.com/offirgolan)*
#### Commits
- [8b80d645](https://github.com/offirgolan/ember-light-table/commit/8b80d645c59efbb37d2b92e9e839ec2bbcd29ae2) **make text unselectable if column is sortable** *by [Ben Limmer](https://github.com/blimmer)*
## v1.0.1
- [#101](https://github.com/offirgolan/ember-light-table/pull/101) Always use Ember object `get` by [@blimmer](https://github.com/blimmer)
- [#102](https://github.com/offirgolan/ember-light-table/pull/102) Use ember-font-awesome vs. ember-cli-font-awesome by [@blimmer](https://github.com/blimmer)
## v1.0.0
- [#30](https://github.com/offirgolan/ember-light-table/pull/30) Support custom cell and column types
- [#38](https://github.com/offirgolan/ember-light-table/pull/38) Add table reference to custom column components
- [#40](https://github.com/offirgolan/ember-light-table/pull/40) Use native Ember trackpad scroll emulator via ember-scrollable - [@taras](https://github.com/taras)
- [#42](https://github.com/offirgolan/ember-light-table/pull/42) Add hideable option to columns
__BREAKING CHANGES__
1. `headerComponent` in column definition has been renamed to `component`
2. `onScrolledToBottom` action has been moved from `{{light-table}}` to `{{t.body}}` component
3. `height` has been moved from `{{t.body}}` to `{{light-table}}` component
## v0.1.9
- Remove tag-less cell component since it was restricting a bunch of Ember.Component features such as class name bindings, events, etc.
## v0.1.8
- [#14](https://github.com/offirgolan/ember-light-table/pull/14) Table cell performance to decrease render time by almost half
## v0.1.7
- Setup scroll event binding only if action is present
- Add is-expanded css class to row
## v0.1.6
- Rename `formatter` to `format`
## v0.1.5
- Ability to provide a formatter function to column definition that will be used to computed the cell value
## v0.1.4
- [#4](https://github.com/offirgolan/ember-light-table/pull/4) Apply width on cell component based on it's columns width [@steffenbrem](https://github.com/steffenbrem)
- [#5](https://github.com/offirgolan/ember-light-table/issues/5) Add insertRowAt & insertColumnAt to public Table API
- Return pushed/inserted rows & columns from public APIs
## v0.1.3
- Fixed an issue where cell value was not bound
## v0.1.2
- Ability to push rows using ArrayProxy instances
## v0.1.1
- [#1](https://github.com/offirgolan/ember-light-table/issues/1) Add default CSS
## v0.1.0
- Initial Release
================================================
FILE: CONTRIBUTING.md
================================================
# How To Contribute
## Installation
* `git clone <repository-url>`
* `cd ember-light-table`
* `yarn install`
## Linting
* `yarn lint`
* `yarn lint:fix`
## Running tests
* `ember test` – Runs the test suite on the current Ember version
* `ember test --server` – Runs the test suite in "watch mode"
* `ember try:each` – Runs the test suite against multiple Ember versions
## Running the dummy application
* `ember serve`
* Visit the dummy application at [http://localhost:4200](http://localhost:4200).
For more information on using ember-cli, visit [https://cli.emberjs.com/release/](https://cli.emberjs.com/release/).
================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
Copyright (c) 2016 - 2019
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
<div align="center">
<a href="https://adopted-ember-addons.github.io/ember-light-table/">
<img
src="https://github.com/adopted-ember-addons/ember-light-table/master/docs/readme-logo.png"
alt="Ember Light Table"
>
</a>
</div>
[](https://travis-ci.org/offirgolan/ember-light-table)
[](https://travis-ci.org/offirgolan/ember-light-table)
[](http://badge.fury.io/js/ember-light-table)
[](http://badge.fury.io/js/ember-light-table)
[](https://emberobserver.com/addons/ember-light-table)
[](https://codeclimate.com/github/offirgolan/ember-light-table)
**Ember Light Table** is a lightweight contextual component based table addon that follows Ember's actions up, data down ideology.
# WARNING
_The API for initializing Ember Light Table (v2.x) has recently changed. Please review the [Pull Request](https://github.com/adopted-ember-addons/ember-light-table/pull/701) for more information._
## Features
- Custom component based column headers and cells
- Infinite scroll support
- Select & Multi-select with keyboard support (CMD/CTRL, SHIFT)
- Fixed header and footer
- Grouped columns
- Resizable columns
- Expandable rows
- Responsive
- Scroll Tracking
- 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://adopted-ember-addons.github.io/ember-light-table/#/cookbook/occlusion-rendering).
Compatibility
------------------------------------------------------------------------------
* Ember.js v3.24 or above
* Ember CLI v3.24 or above
* Node.js v14 or above
Installation
------------------------------------------------------------------------------
```shell
ember install ember-light-table
```
## :link: Helpful Links
- :rocket: [Live Demo][demo]
- :books: [API Documentation][docs]
- :pencil: [Changelog](CHANGELOG.md)
## :sos: Looking for Help?
- :warning: **Bug reports**: If your bug hasn't been reported yet, please [**open an issue**][new-issue]. Try to pick a short but descriptive title. Make sure you're using the latest version of *ember-light-table*. In the issue body, try to provide exact steps for reproduction, ideally with example code. If you can't, please include any and all error messages, as many details as possible and exact information on which Ember.js / ember-cli version and browser / OS you're using.
- :question: **Questions**: As with bugs, please make sure the question wasn't asked before. Also, see if the [Live Demo][demo], [Cookbook][cookbook] or [API docs][docs] already cover your problem. If not, please do [**open an issue**][new-issue].
-  Join Ember on [Discord](https://discord.gg/zT3asNS). We're happy to help you there!
## :metal: Getting Involved
We're glad you love *ember-light-table* just as much as we do! If you want to help us making it even better, we would be delighted to have you on board, even if you've just started using Ember.
### :bulb: Submitting Ideas
If you've got a great idea in store, but don't feel up for the task to implement it yourself, just [**open an issue**][new-issue]. That way you can put your thoughts out there for discussion and we can evolve it further.
We'll see, whether this feature is a good fit for *ember-light-table* itself or could better be implemented in a third-party addon.
You're also always invited to chime in on ongoing issues, *especially* for issues marked with [**ideas-wanted**][ideas-wanted].
### :keyboard: Contributing Code
Contributing to an Ember addon is a great opportunity to get in touch with advanced concepts. You're also getting free peer review for your code as a bonus!
And most importantly, you're doing something good for the community!
#### :sparkles: New Features
If you want to make a bigger change, we recommend [**opening an issue**][new-issue] first, so we can agree on the best possible implementation first and none of your work goes to waste.
#### :eyes: Don't know where to start?
You don't have a specific feature in mind but want to help out anyways? Awesome!
Issues marked with [**help wanted**][help-wanted] are generally agreed upon and ready to get implemented. Oftentimes we have clearly outlined how these issues should get resolved.
#### :handshake: Got Stuck?
We're here to help! It's a good idea to submit you're pull request (PR) right away. Just prefix the title with `[WIP]` (work in progress) so we know that you're not done yet.
This way, you can get feedback early on or ask others for help. Your commits are also automatically tested by Travis CI. :robot:
Pull requests marked with [**ideas-wanted**][pr-ideas-wanted] are stuck and we would like to hear your thought.
If a pull request is marked with [**help wanted**][pr-help-wanted] we just don't have the time and resources to work on it right now. You're invited to continue working on it instead!
[new-issue]: https://github.com/offirgolan/ember-light-table/issues/new
[ideas-wanted]: https://github.com/offirgolan/ember-light-table/issues?q=is%3Aissue+is%3Aopen+label%3Aideas-wanted
[help-wanted]: https://github.com/offirgolan/ember-light-table/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22
[pr-ideas-wanted]: https://github.com/offirgolan/ember-light-table/pulls?q=is%3Apr+is%3Aopen+label%ideas-wanted
[pr-help-wanted]: https://github.com/offirgolan/ember-light-table/pulls?q=is%3Apr+is%3Aopen+label%3Ahelp+wanted
[demo]: https://adopted-ember-addons.github.io/ember-light-table/
[cookbook]: https://adopted-ember-addons.github.io/ember-light-table/#/cookbook
[docs]: https://adopted-ember-addons.github.io/ember-light-table/docs/
================================================
FILE: RELEASE.md
================================================
# Release Process
Releases are mostly automated using
[release-it](https://github.com/release-it/release-it/) and
[lerna-changelog](https://github.com/lerna/lerna-changelog/).
## Preparation
Since the majority of the actual release process is automated, the primary
remaining task prior to releasing is confirming that all pull requests that
have been merged since the last release have been labeled with the appropriate
`lerna-changelog` labels and the titles have been updated to ensure they
represent something that would make sense to our users. Some great information
on why this is important can be found at
[keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall
guiding principle here is that changelogs are for humans, not machines.
When reviewing merged PR's the labels to be used are:
* breaking - Used when the PR is considered a breaking change.
* enhancement - Used when the PR adds a new feature or enhancement.
* bug - Used when the PR fixes a bug included in a previous release.
* documentation - Used when the PR adds or updates documentation.
* internal - Used for internal changes that still require a mention in the
changelog/release notes.
## Release
Once the prep work is completed, the actual release is straight forward:
* First, ensure that you have installed your projects dependencies:
```sh
yarn install
```
* Second, ensure that you have obtained a
[GitHub personal access token][generate-token] with the `repo` scope (no
other permissions are needed). Make sure the token is available as the
`GITHUB_AUTH` environment variable.
For instance:
```bash
export GITHUB_AUTH=abc123def456
```
[generate-token]: https://github.com/settings/tokens/new?scopes=repo&description=GITHUB_AUTH+env+variable
* And last (but not least 😁) do your release.
```sh
npx release-it
```
[release-it](https://github.com/release-it/release-it/) manages the actual
release process. It will prompt you to to choose the version number after which
you will have the chance to hand tweak the changelog to be used (for the
`CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging,
pushing the tag and commits, etc.
================================================
FILE: addon/-private/global-options.js
================================================
import config from 'ember-get-config';
const globalOptions = config['ember-light-table'] || {};
export default globalOptions;
export function mergeOptionsWithGlobals(options) {
return Object.assign({}, globalOptions, options);
}
================================================
FILE: addon/.gitkeep
================================================
================================================
FILE: addon/classes/Column.js
================================================
import { A as emberArray, makeArray } from '@ember/array';
import EmberObject, { computed } from '@ember/object';
import { notEmpty, or } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import { guidFor } from '@ember/object/internals';
import classic from 'ember-classic-decorator';
/**
* @module Table
* @class Column
*/
@classic
export default class Column extends EmberObject.extend({
/**
* Whether the column can be hidden.
*
* CSS Classes:
* - `is-hideable`
*
* @property hideable
* @type {Boolean}
* @default true
*/
hideable: true,
/**
* Whether the column can is hidden.
*
* CSS Classes:
* - `is-hidden`
*
* @property hidden
* @type {Boolean}
* @default false
*/
hidden: false,
/**
* If true, this column has been hidden due to the responsive behavior
*
* @property responsiveHidden
* @type {Boolean}
* @default false
*/
responsiveHidden: false,
/**
* @property ascending
* @type {Boolean}
* @default true
*/
ascending: true,
/**
* Whether the column can be sorted.
*
* CSS Classes:
* - `is-sortable`
*
* @property sortable
* @type {Boolean}
* @default true
*/
sortable: true,
/**
* Whether the column can be resized.
*
* CSS Classes:
* - `is-resizable`
* - `is-resizing`
*
* @property resizable
* @type {Boolean}
* @default false
*/
resizable: false,
/**
* Whether the column can be reorder via drag and drop.
*
* CSS Classes:
* - `is-draggable`
* - `is-dragging`
* - `is-drag-target`
* - `drag-left`
* - `drag-right`
*
* @property draggable
* @type {Boolean}
* @default false
*/
draggable: false,
/**
* Whether the column is a valid drop target.
*
* @property droppable
* @type {Boolean}
* @default true
*/
droppable: true,
/**
* Whether the column is sorted.
*
* CSS Classes:
* - `is-sorted`
*
* @property sorted
* @type {Boolean}
* @default false
*/
sorted: false,
/**
* Column header label
* @property label
* @type {String}
* @default ''
*/
label: '',
/**
* Text alignment. Possible values are ['left', 'right', 'center']
* @property align
* @type {String}
* @default 'left'
*/
align: 'left',
/**
* The minimum width (in px) that this column can be resized to.
* @property minResizeWidth
* @type {Number}
* @default 0
*/
minResizeWidth: 0,
/**
* The parent column (or group) for this sub-column.
* This will only have a value if this column is a sub-column.
* Note: this doesn't update if you move this sub-column to another parent after instantiation.
*
* @property parent
* @type Column
* @optional
*/
parent: null,
/**
* An array of sub columns to be grouped together
* @property subColumns
* @type {Array}
* @optional
*/
subColumns: null,
/**
* An array of media breakpoints that determine when this column will be shown
*
* If we have the following breakpoints defined in `app/breakpoints.js`:
*
* - mobile
* - tablet
* - desktop
*
* And we want to show this column only for tablet and desktop media, the following
* array should be specified: `['tablet', 'desktop']`.
*
* If this property is `null`, `undefined`, or `[]`, then this column will always
* be shown, regardless of the current media type.
*
* @property breakpoints
* @type {Array}
* @optional
*/
breakpoints: null,
/**
* Type of column component
*
* You can create your own column types by running the blueprint:
* `ember g column-type my-column-type`
*
* This will generate a component for you which represents the `<th>`
* element for the column. If you want to apply custom actions to the `th`,
* or do some custom styling of the `th` with classNameBindings, all of that is
* available to you in this component.
*
* You can then specify the custom type you created as a string here, to use it.
*
*
* @property type
* @type {String}
* @default 'base'
*/
type: 'base',
/**
* Type of cell component
*
* You can create your own cell types by running the blueprint:
* `ember g cell-type my-cell-type`
*
* This will generate a component for you which represents the `<td>`
* cells in the column. If you want to apply custom actions to the `td`,
* or do some custom styling of the `td` with classNameBindings, all of that is
* available to you in this component.
*
* You can then specify the custom type you created as a string here, to use it.
*
* @property cellType
* @type {String}
* @default 'base'
*/
cellType: 'base',
/**
* Component name for the column
* @property component
* @type {String}
* @optional
*/
component: null,
/**
* Component name for the column cells. This component is automatically passed row,
* column, and value variables, and you can specify a valuePath to set what property
* the value is set to.
* @property cellComponent
* @type {String}
* @optional
*/
cellComponent: null,
/**
* @property valuePath
* @type {String}
*/
valuePath: null,
/**
* @property width
* @type {String}
*/
width: null,
/**
* Class names to be applied to header and footer cells of this column
*
* @property classNames
* @type {String | Array}
*/
classNames: null,
/**
* Class names to be applied to all cells of this column
*
* @property cellClassNames
* @type {String | Array}
*/
cellClassNames: null,
/**
* A format function used to calculate a cell's value. This method will be passed
* the raw value if `valuePath` is specified.
*
* @property format
* @type {Function}
*/
format: null,
/**
* Column's unique ID.
*
* @property columnId
* @type {String}
* @private
*/
columnId: computed(function () {
return guidFor(this);
}).readOnly(),
/**
* True if `hidden` or `responsiveHidden` is true.
* @property isHidden
* @type {Boolean}
*/
isHidden: or('hidden', 'responsiveHidden'),
/**
* @property isGroupColumn
* @type {Boolean}
* @private
*/
isGroupColumn: notEmpty('subColumns'),
/**
* @property isVisibleGroupColumn
* @type {Boolean}
* @private
*/
isVisibleGroupColumn: computed(
'visibleSubColumns.[]',
'isHidden',
function () {
return !isEmpty(this.visibleSubColumns) && !this.isHidden;
}
).readOnly(),
/**
* @property visibleSubColumns
* @type {Array}
* @private
*/
visibleSubColumns: computed(
'subColumns.@each.isHidden',
'isHidden',
function () {
let subColumns = this.subColumns;
let isHidden = this.isHidden;
return emberArray(isHidden ? [] : subColumns.filterBy('isHidden', false));
}
).readOnly(),
init(options = {}) {
this.setProperties(options);
const subColumns = emberArray(
makeArray(this.subColumns).map((sc) => Column.create(sc))
);
subColumns.setEach('parent', this);
this.set('subColumns', subColumns);
},
}) {}
================================================
FILE: addon/classes/Row.js
================================================
import ObjectProxy from '@ember/object/proxy';
import { computed } from '@ember/object';
import { guidFor } from '@ember/object/internals';
import classic from 'ember-classic-decorator';
/**
* @module Table
* @extends Ember.ObjectProxy
* @class Row
*/
@classic
export default class Row extends ObjectProxy.extend({
/**
* Whether the row is hidden.
*
* CSS Classes:
* - `is-hidden`
*
* @property hidden
* @type {Boolean}
* @default false
*/
hidden: false,
/**
* Whether the row is expanded.
*
* CSS Classes:
* - `is-expanded`
*
* @property expanded
* @type {Boolean}
* @default false
*/
expanded: false,
/**
* Whether the row is selected.
*
* CSS Classes:
* - `is-selected`
*
* @property selected
* @type {Boolean}
* @default false
*/
selected: false,
/**
* Class names to be applied to this row
*
* @property classNames
* @type {String | Array}
*/
classNames: null,
/**
* Data content for this row. Since this class extends Ember.ObjectProxy,
* all properties are forwarded to the content. This means that instead of
* `row.content.foo` you can just do `row.foo`. Please note that methods are
* not forwarded. You will not be able to do `row.save()`, instead, you would have
* to do `row.content.save()`.
*
* @property content
* @type {Object}
*/
content: null,
/**
* Rows's unique ID.
*
* Note: named `rowId` in order to not shadow the `content.id` property.
*
* @property rowId
* @type {String}
* @readOnly
*/
rowId: computed(function () {
return guidFor(this);
}).readOnly(),
}) {}
================================================
FILE: addon/classes/Table.js
================================================
import { A as emberArray, isArray } from '@ember/array';
import { assert } from '@ember/debug';
import EmberObject, { computed } from '@ember/object';
import { empty, filterBy } from '@ember/object/computed';
import Row from 'ember-light-table/classes/Row';
import Column from 'ember-light-table/classes/Column';
import { mergeOptionsWithGlobals } from 'ember-light-table/-private/global-options';
import { isNone } from '@ember/utils';
import classic from 'ember-classic-decorator';
/**
* @module Table
* @private
*/
/**
* @module Table
* @class Table
*/
@classic
export default class Table extends EmberObject.extend({
/**
* @property columns
* @type {Ember.Array}
* @default []
*/
columns: null,
/**
* @property rows
* @type {Ember.Array}
* @default []
*/
rows: null,
/**
* @property isEmpty
* @type {Boolean}
*/
isEmpty: empty('rows').readOnly(),
/**
* @property expandedRows
* @type {Ember.Array}
*/
expandedRows: filterBy('rows', 'expanded', true).readOnly(),
/**
* @property selectedRows
* @type {Ember.Array}
*/
selectedRows: filterBy('rows', 'selected', true).readOnly(),
/**
* @property visibleRows
* @type {Ember.Array}
*/
visibleRows: filterBy('rows', 'hidden', false).readOnly(),
/**
* @property sortableColumns
* @type {Ember.Array}
*/
sortableColumns: filterBy('visibleColumns', 'sortable', true).readOnly(),
/**
* @property sortedColumns
* @type {Ember.Array}
*/
sortedColumns: filterBy('visibleColumns', 'sorted', true).readOnly(),
/**
* @property hideableColumns
* @type {Ember.Array}
*/
hideableColumns: filterBy('allColumns', 'hideable', true).readOnly(),
/**
* @property hiddenColumns
* @type {Ember.Array}
*/
hiddenColumns: filterBy('allColumns', 'hidden', true).readOnly(),
/**
* @property responsiveHiddenColumns
* @type {Ember.Array}
*/
responsiveHiddenColumns: filterBy(
'allColumns',
'responsiveHidden',
true
).readOnly(),
/**
* @property visibleColumns
* @type {Ember.Array}
*/
visibleColumns: filterBy('allColumns', 'isHidden', false).readOnly(),
/**
* @property visibleColumnGroups
* @type {Ember.Array}
*/
visibleColumnGroups: computed(
'columns.[]',
'columns.@each.{isHidden,isVisibleGroupColumn}',
function () {
return this.columns.reduce((arr, c) => {
if (
c.get('isVisibleGroupColumn') ||
(!c.get('isGroupColumn') && !c.get('isHidden'))
) {
arr.pushObject(c);
}
return arr;
}, emberArray([]));
}
).readOnly(),
/**
* @property visibleSubColumns
* @type {Ember.Array}
*/
visibleSubColumns: computed('columns.@each.visibleSubColumns', function () {
return emberArray([].concat(...this.columns.getEach('visibleSubColumns')));
}).readOnly(),
/**
* @property allColumns
* @type {Ember.Array}
*/
allColumns: computed('columns.@each.subColumns', function () {
return this.columns.reduce((arr, c) => {
arr.pushObjects(c.get('isGroupColumn') ? c.get('subColumns') : [c]);
return arr;
}, emberArray([]));
}).readOnly(),
/**
* @class Table
* @constructor
* @param {Object} options
* @param {Array} options.columns
* @param {Array} options.rows
* @param {Object} options.rowOptions Options hash passed through to
* `createRow(content, options)`.
*/
init(options = {}) {
let { columns = [], rows = [] } = options;
assert(
'[ember-light-table] columns must be an array if defined',
isArray(columns)
);
assert(
'[ember-light-table] rows must be an array if defined',
isArray(rows)
);
this.setProperties(mergeOptionsWithGlobals(options));
this.set('columns', emberArray(Table.createColumns(columns)));
let _rows = emberArray(Table.createRows(rows, this.rowOptions));
this.set('rows', _rows);
},
}) {
// Rows
/**
* Replace all the row's content with content of the argument. If argument is an empty array rows will be cleared.
* @method setRows
* @param {Array} rows
* @param {Object} options
* @return {Array} rows
*/
setRows(rows = [], options = {}) {
return this.rows.setObjects(Table.createRows(rows, options));
}
/**
* Push the object onto the end of the row array if it is not already present.
* @method addRow
* @param {Object} row
* @param {Object} options
*/
addRow(row, options = {}) {
if (row instanceof Row) {
this.rows.addObject(row);
} else if (isNone(this.rows.findBy('content', row))) {
this.pushRow(row, options);
}
}
/**
* Push the objects onto the end of the row array if it is not already present.
* @method addRows
* @param {Array} rows
* @param {Object} options
*/
addRows(rows = [], options = {}) {
rows.forEach((r) => this.addRow(r, options));
}
/**
* Push the object onto the end of the row array.
* @method pushRow
* @param {Object} row
* @param {Object} options
* @return {Row} pushed row
*/
pushRow(row, options = {}) {
let _row = Table.createRow(row, options);
this.rows.pushObject(_row);
return _row;
}
/**
* Push the object onto the end of the row array.
* @method pushRows
* @param {Array} rows
* @param {Object} options
* @return {Array} pushed rows
*/
pushRows(rows = [], options = {}) {
let _rows = Table.createRows(rows, options);
this.rows.pushObjects(_rows);
return _rows;
}
/**
* Insert a row at the specified index.
* @method insertRowAt
* @param {Number} index
* @param {Object} row
* @param {Object} options
* @return {Row} inserted row
*/
insertRowAt(index, row, options = {}) {
let _row = Table.createRow(row, options);
this.rows.insertAt(index, _row);
return _row;
}
/**
* Remove all occurrences of an object in the rows
* @method removeRow
* @param {Object} row
*/
removeRow(row) {
if (row instanceof Row) {
this.rows.removeObject(row);
} else {
this.rows.removeObjects(this.rows.filterBy('content', row));
}
}
/**
* Removes each object in the passed enumerable from the rows.
* @method removeRows
* @param {Array} rows
*/
removeRows(rows = []) {
rows.forEach((r) => this.removeRow(r));
}
/**
* Remove a row at the specified index
* @method removeRowAt
* @param {Number} index
*/
removeRowAt(index) {
this.rows.removeAt(index);
}
// Columns
/**
* Replace all the column's content with content of the argument. If argument is an empty array columns will be cleared.
* @method setColumns
* @param {Array} columns
* @return {Array} columns
*/
setColumns(columns = []) {
return this.columns.setObjects(Table.createColumns(columns));
}
/**
* Push the object onto the end of the column array if it is not already present.
* @method addColumn
* @param {Object} column
*/
addColumn(column) {
this.columns.addObject(Table.createColumn(column));
}
/**
* Push the objects onto the end of the column array if it is not already present.
* @method addColumns
* @param {Array} columns
*/
addColumns(columns = []) {
this.columns.addObjects(Table.createColumns(columns));
}
/**
* Push the object onto the end of the column array.
* @method pushColumn
* @param {Object} column
* @return {Column} pushed column
*/
pushColumn(column) {
let _column = Table.createColumn(column);
this.columns.pushObject(_column);
return _column;
}
/**
* Push the object onto the end of the column array.
* @method pushColumns
* @param {Array} columns
* @return {Array} pushed columns
*/
pushColumns(columns = []) {
let _columns = Table.createColumns(columns);
this.columns.pushObjects(_columns);
return _columns;
}
/**
* Insert a column at the specified index.
* @method insertColumnAt
* @param {Number} index
* @param {Object} column
* @return {Column} inserted column
*/
insertColumnAt(index, column) {
let _column = Table.createColumn(column);
this.columns.insertAt(index, _column);
return _column;
}
/**
* Remove all occurrences of an object in the columns
* @method removeColumn
* @param {Object} column
*/
removeColumn(column) {
return this.columns.removeObject(column);
}
/**
* Removes each object in the passed enumerable from the columns.
* @method removeColumns
* @param {Array} columns
*/
removeColumns(columns = []) {
return this.columns.removeObjects(columns);
}
/**
* Remove a column at the specified index
* @method removeColumnAt
* @param {Number} index
*/
removeColumnAt(index) {
this.columns.removeAt(index);
}
/**
* Create a Row object with the given content
* @method createRow
* @static
* @param {Object} content
* @param {Object} options
* @return {Row}
*/
static createRow(content, options = {}) {
if (content instanceof Row) {
return content;
} else {
return Row.create(Object.assign({}, options, { content }));
}
}
/**
* Create a collection of Row objects with the given collection
* @method createRows
* @static
* @param {Array} rows
* @param {Object} options
* @return {Array}
*/
static createRows(rows = [], options = {}) {
return rows.map((r) => Table.createRow(r, options));
}
/**
* Create a Column object with the given options
* @method createColumn
* @static
* @param {Object} column
* @return {Column}
*/
static createColumn(column) {
if (column instanceof Column) {
return column;
} else {
return Column.create(column);
}
}
/**
* Create a collection of Column objects with the given collection
* @method createColumns
* @static
* @param {Array} columns
* @return {Array}
*/
static createColumns(columns = []) {
return columns.map((c) => Table.createColumn(c));
}
}
================================================
FILE: addon/components/cells/base.hbs
================================================
{{#if this.column.cellComponent}}
{{component
(ensure-safe-component this.column.cellComponent)
tableActions=this.tableActions
extra=this.extra
table=this.table
column=this.column
row=this.row
value=this.value
rawValue=this.rawValue
}}
{{else}}
{{this.value}}
{{/if}}
================================================
FILE: addon/components/cells/base.js
================================================
import Component from '@ember/component';
import { computed } from '@ember/object';
import { readOnly } from '@ember/object/computed';
import { htmlSafe } from '@ember/template';
/**
* @module Light Table
* @submodule Cell Types
*/
/**
* @module Cell Types
* @class Base Cell
*/
export default Component.extend({
tagName: 'td',
classNames: ['lt-cell'],
attributeBindings: ['style'],
classNameBindings: ['align', 'isSorted', 'column.cellClassNames'],
enableScaffolding: false,
isSorted: readOnly('column.sorted'),
style: computed('enableScaffolding', 'column.width', function () {
let column = this.column;
let columnWidth = column.get('width');
if (this.enableScaffolding || !column) {
return;
}
// For performance reasons, it's more interesting to bypass cssStyleify
// since it leads to a lot of garbage collections
// when displaying many cells
return columnWidth ? htmlSafe(`width: ${columnWidth};`) : null;
}),
align: computed('column.align', function () {
return `align-${this.column.align}`;
}),
/**
* @property table
* @type {Table}
*/
table: null,
/**
* @property column
* @type {Column}
*/
column: null,
/**
* @property row
* @type {Row}
*/
row: null,
/**
* @property tableActions
* @type {Object}
*/
tableActions: null,
/**
* @property extra
* @type {Object}
*/
extra: null,
/**
* @property rawValue
* @type {Mixed}
*/
rawValue: null,
/**
* @property value
* @type {Mixed}
*/
value: computed('column.format', 'rawValue', function () {
let rawValue = this.rawValue;
let format = this.column.format;
if (format && typeof format === 'function') {
return format.call(this, rawValue);
}
return rawValue;
}),
});
================================================
FILE: addon/components/columns/base.hbs
================================================
{{#if this.column.component}}
{{component
(ensure-safe-component this.column.component)
column=this.column
table=this.table
tableActions=this.tableActions
extra=this.extra
sortIcons=this.sortIcons
}}
{{else}}
{{#if (and this.sortIcons.iconComponent this.sortIconProperty)}}
{{component
(ensure-safe-component this.sortIcons.iconComponent)
sortIcons=this.sortIcons
sortIconProperty=this.sortIconProperty
}}
{{else if this.sortIconProperty}}
<i class='lt-sort-icon {{get this.sortIcons this.sortIconProperty}}'></i>
{{/if}}
{{this.label}}
{{/if}}
{{#if this.isResizable}}
<LtColumnResizer
@column={{this.column}}
@table={{this.table}}
@resizeOnDrag={{this.resizeOnDrag}}
@isResizing={{mut this.isResizing}}
@onColumnResized={{action this.onColumnResized this.column}}
/>
{{/if}}
================================================
FILE: addon/components/columns/base.js
================================================
import { set } from '@ember/object';
import Component from '@ember/component';
import { computed } from '@ember/object';
import { oneWay, readOnly } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import DraggableColumnMixin from 'ember-light-table/mixins/draggable-column';
import cssStyleify from 'ember-light-table/utils/css-styleify';
/**
* @module Light Table
* @submodule Column Types
*/
/**
* @module Column Types
* @class Base Column
*/
export default Component.extend(DraggableColumnMixin, {
tagName: 'th',
classNames: ['lt-column'],
attributeBindings: ['style', 'colspan', 'rowspan'],
classNameBindings: [
'align',
'isGroupColumn:lt-group-column',
'isHideable',
'isSortable',
'isSorted',
'isResizable',
'isResizing',
'isDraggable',
'column.classNames',
],
isGroupColumn: readOnly('column.isGroupColumn'),
isSortable: readOnly('column.sortable'),
isSorted: readOnly('column.sorted'),
isHideable: readOnly('column.hideable'),
isResizable: readOnly('column.resizable'),
isDraggable: readOnly('column.draggable'),
isResizing: false,
style: computed('column.width', function () {
return cssStyleify(this.column.getProperties(['width']));
}),
align: computed('column.align', function () {
return `align-${this.column.align}`;
}),
/**
* @property label
* @type {String}
*/
label: oneWay('column.label'),
/**
* @property table
* @type {Table}
*/
table: null,
/**
* @property column
* @type {Column}
*/
column: null,
/**
* @property tableActions
* @type {Object}
*/
tableActions: null,
/**
* @property extra
* @type {Object}
*/
extra: null,
/**
* @property sortIcons
* @type {Object}
*/
sortIcons: null,
/**
* @property sortIconProperty
* @type {String|null}
* @private
*/
sortIconProperty: computed('column.{sortable,sorted,ascending}', function () {
let sorted = this.column.sorted;
if (sorted) {
let ascending = this.column.ascending;
return ascending ? 'iconAscending' : 'iconDescending';
}
let sortable = this.column.sortable;
return sortable ? 'iconSortable' : null;
}),
/**
* @property colspan
* @type {Number}
*/
colspan: computed('column', 'column.visibleSubColumns.[]', function () {
let subColumns = this.column.visibleSubColumns;
return !isEmpty(subColumns) ? subColumns.length : 1;
}),
/**
* @property rowspan
* @type {Number}
*/
rowspan: computed('_rowspan', 'column.visibleSubColumns.[]', {
get() {
if (this._rowspan) {
return this._rowspan;
}
let subColumns = this.column.visibleSubColumns;
return !isEmpty(subColumns) ? 1 : 2;
},
set(key, value) {
return set(this, '_rowspan', value);
},
}),
});
================================================
FILE: addon/components/light-table.hbs
================================================
<div
class="ember-light-table {{if this.occlusion "occlusion"}}"
id={{or @id this.tableId}}
style={{this.style}}
...attributes
>
{{yield
(hash
head=(component
"lt-head"
tableId=(or @id this.tableId)
table=this.table
tableActions=this.tableActions
extra=this.extra
tableClassNames=this.tableClassNames
sharedOptions=this.sharedOptions
)
body=(component
"lt-body"
tableId=(or @id this.tableId)
table=this.table
tableActions=this.tableActions
extra=this.extra
tableClassNames=this.tableClassNames
sharedOptions=this.sharedOptions
)
foot=(component
"lt-foot"
tableId=(or @id this.tableId)
table=this.table
tableActions=this.tableActions
extra=this.extra
tableClassNames=this.tableClassNames
sharedOptions=this.sharedOptions
)
)
}}
</div>
================================================
FILE: addon/components/light-table.js
================================================
import { A as emberArray } from '@ember/array';
import Component from '@ember/component';
import { computed, observer } from '@ember/object';
import { readOnly } from '@ember/object/computed';
import { guidFor } from '@ember/object/internals';
import { isEmpty, isNone } from '@ember/utils';
import { assert } from '@ember/debug';
import { inject as service } from '@ember/service';
import Table from 'ember-light-table/classes/Table';
import cssStyleify from 'ember-light-table/utils/css-styleify';
function intersections(array1, array2) {
return array1.filter((n) => {
return array2.indexOf(n) > -1;
});
}
/**
* @module Light Table
* @main light-table
*/
/**
* ```hbs
* <LightTable @table={{this.table}} as |t| >
* <t.head />
* <t.nody />
* <t.foot />
* </LightTable>
* ```
*
* Please see the documentation for the [Head](../classes/t.head.html), [Body](../classes/t.body.html), and [Foot](../classes/t.foot.html) components
* for more details on all possible options and actions.
*
* @class light-table
* @main Components
*/
export default Component.extend({
tagName: '',
media: service(),
scrollbarThickness: service(),
/**
* @property table
* @type {Table}
*/
table: null,
/**
* This is used to propagate custom user defined actions to custom cell and header components.
* As an example, lets say I have a table with a column defined with `cellComponent: 'delete-user'`
*
* ```hbs
* <LightTable
* @table={{this.table}}
* @tableActions={{hash deleteUser=this.deleteUser}}
* as |t|
* >
* <t.head />
* <t.body />
* <t.foot />
* </LightTable>
* ```
*
* Now in the `delete-user` component, we can access that `deleteUser` action and pass it the
* row object which will bubble all the way to where you defined that action.
*
* ```hbs
* * <button {{on 'click' (fn @tableActions.deleteUser @row)}}>Delete Me</button>
* ```
*
*
* @property tableActions
* @type {Object}
*/
tableActions: null,
/**
* Object to store any arbitrary configuration meant to be used by custom
* components.
*
* ```hbs
* <LightTable @table={{this.table}}
* @extra={{hash
* highlightColor="yellow"
* }}
* as |t|
* }}
* <t.head />
* <t.body />
* <t.foot />
* </LightTable>
* ```
*
* Now in all custom components, you can access this value like so:
*
* ```hbs
* <span style="background: {{extra.highlightColor}}">{{value}}<span>
* ```
*
* @property extra
* @type {Object}
*/
extra: null,
/**
* Table height.
*
* @property height
* @type {String}
* @default null
*/
height: null,
/**
* Class names that will be added to all <table> tags
*
* @property tableClassNames
* @type {String}
* @default ''
*/
tableClassNames: '',
/**
* Enable responsive behavior
*
* @property responsive
* @type {Boolean}
* @default false
*/
responsive: false,
/**
* A hash to determine the number of columns to show per given breakpoint.
* If this is specified, it will override any column specific breakpoints.
*
* If we have the following breakpoints defined in `app/breakpoints.js`:
*
* - mobile
* - tablet
* - desktop
*
* The following hash can be passed in:
*
* ```js
* {
* mobile: 2,
* tablet: 4
* }
* ```
*
* If there is no rule specified for a given breakpoint (i.e. `desktop`),
* all columns will be shown.
*
* @property breakpoints
* @type {Object}
* @default null
*/
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,
/**
* Whether `vertical-collection` should recycle table rows. This speeds up performance with occlusion
* rendering but may cause problems if any components expect to reset their state to the initial state
* with every rerender of the list.
*
* @property shouldRecycle
* @type Boolean
* @default true
*/
shouldRecycle: true,
/**
* Table component shared options
*
* @property sharedOptions
* @type {Object}
* @private
*/
sharedOptions: computed(
'estimatedRowHeight',
'height',
'occlusion',
'shouldRecycle',
function () {
return {
height: this.height,
fixedHeader: false,
fixedFooter: false,
occlusion: this.occlusion,
estimatedRowHeight: this.estimatedRowHeight,
shouldRecycle: this.shouldRecycle,
};
}
).readOnly(),
visibleColumns: readOnly('table.visibleColumns'),
/**
* Calculates the total width of the visible columns via their `width`
* propert.
*
* Returns 0 for the following conditions
* - All widths are not set
* - Widths are not the same unit
* - Unit cannot be determined
*
* @property totalWidth
* @type {Number}
* @private
*/
totalWidth: computed('visibleColumns.@each.width', function () {
let visibleColumns = this.visibleColumns;
let widths = visibleColumns.getEach('width');
let unit = (widths[0] || '').match(/\D+$/);
let totalWidth = 0;
if (isEmpty(unit)) {
return 0;
}
unit = unit[0];
/*
1. Check if all widths are present
2. Check if all widths are the same unit
*/
for (let i = 0; i < widths.length; i++) {
let width = widths[i];
if (isNone(width) || width.indexOf(unit) === -1) {
return 0;
}
totalWidth += parseInt(width, 10);
}
return `${totalWidth}${unit}`;
}),
style: computed(
'height',
'occlusion',
'scrollbarThickness.thickness',
'totalWidth',
function () {
let totalWidth = this.totalWidth;
let style = { height: this.height };
if (totalWidth) {
if (this.occlusion) {
const scrollbarThickness = this.scrollbarThickness.thickness;
style.width = `calc(${totalWidth} + ${scrollbarThickness}px)`;
} else {
style.width = totalWidth;
}
style.overflowX = 'auto';
}
return cssStyleify(style);
}
),
init() {
this._super(...arguments);
let table = this.table;
assert(
'[ember-light-table] table must be an instance of Table',
table instanceof Table
);
this.set('tableId', guidFor(this));
if (isNone(this.media)) {
this.set('responsive', false);
} else {
this.media.on('mediaChanged', () => this.onMediaChange());
}
this.onMediaChange();
},
onMediaChange: observer('table.allColumns.[]', function () {
let responsive = this.responsive;
let matches = this.media.matches;
let breakpoints = this.breakpoints;
let table = this.table;
let numColumns = 0;
if (!responsive) {
return;
}
this.send('onBeforeResponsiveChange', matches);
if (!isNone(breakpoints)) {
Object.keys(breakpoints).forEach((b) => {
if (matches.indexOf(b) > -1) {
numColumns = Math.max(numColumns, breakpoints[b]);
}
});
this._displayColumns(numColumns);
} else {
table.get('allColumns').forEach((c) => {
let breakpoints = c.get('breakpoints');
let isMatch =
isEmpty(breakpoints) ||
intersections(matches, breakpoints).length > 0;
c.set('responsiveHidden', !isMatch);
});
}
this.send('onAfterResponsiveChange', matches);
}),
_displayColumns(numColumns) {
let table = this.table;
let hiddenColumns = table.get('responsiveHiddenColumns');
let visibleColumns = table.get('visibleColumns');
if (!numColumns) {
hiddenColumns.setEach('responsiveHidden', false);
} else if (visibleColumns.length > numColumns) {
emberArray(
visibleColumns.slice(numColumns, visibleColumns.length)
).setEach('responsiveHidden', true);
} else if (visibleColumns.length < numColumns) {
emberArray(
hiddenColumns.slice(0, numColumns - visibleColumns.length)
).setEach('responsiveHidden', false);
}
},
// No-ops for closure actions
onBeforeResponsiveChange() {},
onAfterResponsiveChange() {},
actions: {
/**
* onBeforeResponsiveChange action.
* Called before any column visibility is altered.
*
* @event onBeforeResponsiveChange
* @param {Array} matches list of matching breakpoints
*/
onBeforeResponsiveChange(/* matches */) {
this.onBeforeResponsiveChange(...arguments);
},
/**
* onAfterResponsiveChange action.
* Called after all column visibility has been altered.
*
* @event onAfterResponsiveChange
* @param {Array} matches list of matching breakpoints
*/
onAfterResponsiveChange(/* matches */) {
this.onAfterResponsiveChange(...arguments);
},
},
});
================================================
FILE: addon/components/lt-body.hbs
================================================
<div
class="lt-body-wrap
{{if this.canSelect "can-select"}}
{{if this.multiSelect "multi-select"}}
{{if this.canExpand "can-expand"}}"
{{did-insert this.onRowsChange this.rows}}
{{did-update this.onRowsChange this.rows}}
{{did-insert this.scheduleScrolledToBottom this.rows this.isInViewport}}
{{did-update this.scheduleScrolledToBottom this.rows this.isInViewport}}
{{did-insert this.setupScrollOffset this.scrollTo this.scrollToRow}}
{{did-update this.setupScrollOffset this.scrollTo this.scrollToRow}}
...attributes
>
{{#let
(hash
row=(or this.rowComponent (component "lt-row"))
spanned-row=(or this.spannedRowComponent (component "lt-spanned-row"))
infinity=(or this.infinityComponent (component "lt-infinity"))
) as |lt|
}}
{{#if this.sharedOptions.occlusion}}
<div class="lt-scrollable tse-scrollable vertical-collection">
<div
id={{concat this.tableId "_inline_head"}}
class="lt-inline lt-head"
></div>
<table class={{this.tableClassNames}}>
<tbody class="lt-body">
{{#if this.overwrite}}
{{yield this.columns this.rows}}
{{else}}
{{#vertical-collection
items=this.rows
tagName="vertical-collection"
estimateHeight=this.sharedOptions.estimatedRowHeight
shouldRecycle=this.sharedOptions.shouldRecycle
staticHeight=true
bufferSize=this.scrollBufferRows
containerSelector=".lt-scrollable"
firstVisibleChanged=(action "firstVisibleChanged")
lastVisibleChanged=(action "lastVisibleChanged")
firstReached=(action "firstReached")
lastReached=(action "lastReached") as |row|
}}
{{lt.row
row=row
columns=this.columns
data-row-id=row.rowId
table=this.table
tableActions=this.tableActions
extra=this.extra
enableScaffolding=this.enableScaffolding
canExpand=this.canExpand
canSelect=this.canSelect
click=(action "onRowClick" row)
doubleClick=(action "onRowDoubleClick" row)
}}
{{/vertical-collection}}
{{yield
(hash
loader=(component
(ensure-safe-component lt.spanned-row)
classes="lt-is-loading"
)
no-data=(component
(ensure-safe-component lt.spanned-row) classes="lt-no-data"
)
expanded-row=(component
(ensure-safe-component lt.spanned-row) visible=false
)
)
this.rows
}}
{{/if}}
</tbody>
</table>
<div
id={{concat this.tableId "_inline_foot"}}
class="lt-inline lt-foot"
></div>
</div>
{{else}}
<LtScrollable
@tagName=""
@virtualScrollbar={{this.useVirtualScrollbar}}
@autoHide={{this.autoHideScrollbar}}
@scrollTo={{this.targetScrollOffset}}
@onScrollY={{action "onScroll"}} as |scrollbar|
>
<div
id={{concat this.tableId "_inline_head"}}
class="lt-inline lt-head"
></div>
<table class={{this.tableClassNames}}>
<tbody class="lt-body">
{{#if this.enableScaffolding}}
<tr class="lt-scaffolding-row">
{{#each this.columns as |column|}}
{{! template-lint-disable no-inline-styles }}
<td
style={{
html-safe
(if column.width (concat "width: " column.width))
}}
class="lt-scaffolding"
></td>
{{! template-lint-enable no-inline-styles }}
{{/each}}
</tr>
{{/if}}
{{#if this.overwrite}}
{{yield this.columns this.rows}}
{{else}}
{{#each
(if
scrollbar (compute scrollbar.update this.rows) this.rows
) as |row|
}}
{{lt.row
row=row
columns=this.columns
data-row-id=row.rowId
table=this.table
tableActions=this.tableActions
extra=this.extra
enableScaffolding=this.enableScaffolding
canExpand=this.canExpand
canSelect=this.canSelect
click=(action "onRowClick" row)
doubleClick=(action "onRowDoubleClick" row)
}}
{{yield
(hash
expanded-row=(component
lt.spanned-row
classes="lt-expanded-row"
colspan=this.colspan
yield=row
visible=row.expanded
)
loader=(component
(ensure-safe-component lt.spanned-row) visible=false
)
no-data=(component
(ensure-safe-component lt.spanned-row) visible=false
)
)
this.rows
}}
{{/each}}
{{yield
(hash
loader=(component
(ensure-safe-component lt.spanned-row)
classes="lt-is-loading"
colspan=this.colspan
)
no-data=(component
(ensure-safe-component lt.spanned-row)
classes="lt-no-data"
colspan=this.colspan
)
expanded-row=(component
(ensure-safe-component lt.spanned-row) visible=false
)
)
this.rows
}}
{{/if}}
</tbody>
</table>
{{#if @onScrolledToBottom}}
<lt.infinity
@enterViewport={{this.enterViewport}}
@exitViewport={{this.exitViewport}}
@scrollableContent={{concat "#" this.tableId " .lt-scrollable"}}
/>
{{/if}}
<div
id={{concat this.tableId "_inline_foot"}}
class="lt-inline lt-foot"
></div>
</LtScrollable>
{{/if}}
{{/let}}
</div>
================================================
FILE: addon/components/lt-body.js
================================================
import Component from '@ember/component';
import { action, computed } from '@ember/object';
import { readOnly } from '@ember/object/computed';
import { cancel, debounce, once, schedule, scheduleOnce } from '@ember/runloop';
import Row from 'ember-light-table/classes/Row';
/**
* @module Light Table
*/
/**
* ```hbs
* <LightTable @table={{this.table}} as |t| >
* <t.body @multiSelect={{true}} @onRowClick={{this.rowClicked}} as |body| >
* <body.ExpandedRow as |row| >
* Hello <b>{{row.firstName}}</b>
* </body.ExpandedRow>
*
* {{#if this.isLoading}}
* {{#body.loader}}
* Loading...
* {{/body.loader}}
* {{/if}}
*
* {{#if this.table.isEmpty}}
* {{#body.no-data}}
* No users found.
* {{/body.no-data}}
* {{/if}}
* </t.body>
* </LightTable>
* ```
*
* @class t.body
*/
export default Component.extend({
tagName: '',
/**
* @property table
* @type {Table}
* @private
*/
table: null,
/**
* @property sharedOptions
* @type {Object}
* @private
*/
sharedOptions: null,
/**
* @property tableActions
* @type {Object}
*/
tableActions: null,
/**
* @property extra
* @type {Object}
*/
extra: null,
/**
* @property isInViewport
* @default false
* @type {Boolean}
*/
isInViewport: false,
/**
* Allows a user to select a row on click. All this will do is apply the necessary
* CSS classes and add the row to `table.selectedRows`. If `multiSelect` is disabled
* only one row will be selected at a time.
*
* @property canSelect
* @type {Boolean}
* @default true
*/
canSelect: true,
/**
* Select a row on click. If this is set to `false` and multiSelect is
* enabled, using click + `shift`, `cmd`, or `ctrl` will still work as
* intended, while clicking on the row will not set the row as selected.
*
* @property selectOnClick
* @type {Boolean}
* @default true
*/
selectOnClick: true,
/**
* Allows for expanding row. This will create a new row under the row that was
* clicked with the template provided by `body.expanded-row`.
*
* ```hbs
* <Body.expandedRow as |row| >
* This is the content of the expanded row for {{row.firstName}}
* </Body.expandedRow>
* ```
*
* @property canExpand
* @type {Boolean}
* @default false
*/
canExpand: false,
/**
* Allows a user to select multiple rows with the `ctrl`, `cmd`, and `shift` keys.
* These rows can be easily accessed via `table.get('selectedRows')`
*
* @property multiSelect
* @type {Boolean}
* @default false
*/
multiSelect: false,
/**
* When multiSelect is true, this property determines whether or not `ctrl`
* (or `cmd`) is required to select additional rows, one by one. When false,
* simply clicking on subsequent rows will select or deselect them.
*
* `shift` to select many consecutive rows is unaffected by this property.
*
* @property multiSelectRequiresKeyboard
* @type {Boolean}
* @default true
*/
multiSelectRequiresKeyboard: true,
/**
* Hide scrollbar when not scrolling
*
* @property autoHideScrollbar
* @type {Boolean}
* @default true
*/
autoHideScrollbar: true,
/**
* Allows multiple rows to be expanded at once
*
* @property multiRowExpansion
* @type {Boolean}
* @default true
*/
multiRowExpansion: true,
/**
* Expand a row on click
*
* @property expandOnClick
* @type {Boolean}
* @default true
*/
expandOnClick: true,
/**
* If true, the body block will yield columns and rows, allowing you
* to define your own table body
*
* @property overwrite
* @type {Boolean}
* @default false
*/
overwrite: false,
/**
* If true, the body will prepend an invisible `<tr>` that scaffolds the
* widths of the table cells.
*
* ember-light-table uses [`table-layout: fixed`](https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout).
* This means, that the widths of the columns are defined by the first row
* only. By prepending this scaffolding row, widths of columns only need to
* be specified once.
*
* @property enableScaffolding
* @type {Boolean}
* @default false
*/
enableScaffolding: false,
/**
* ID of main table component. Used to generate divs for ember-wormhole and set scope for scroll observers
*
* @property tableId
* @type {String}
* @private
*/
tableId: null,
/**
* @property scrollBuffer
* @type {Number}
* @default 500
*/
scrollBuffer: 500,
/**
* @property scrollBufferRows
* @type {Number}
* @default 500 / estimatedRowHeight
*/
scrollBufferRows: computed(
'scrollBuffer',
'sharedOptions.estimatedRowHeight',
function () {
return Math.ceil(
this.scrollBuffer / (this.sharedOptions.estimatedRowHeight || 1)
);
}
),
/**
* @property useVirtualScrollbar
* @type {Boolean}
* @default false
* @private
*/
useVirtualScrollbar: false,
/**
* Set this property to scroll to a specific px offset.
*
* This only works when `useVirtualScrollbar` is `true`, i.e. when you are
* using fixed headers / footers.
*
* @property scrollTo
* @type {Number}
* @default null
*/
scrollTo: null,
_scrollTo: null,
/**
* Set this property to a `Row` to scroll that `Row` into view.
*
* This only works when `useVirtualScrollbar` is `true`, i.e. when you are
* using fixed headers / footers.
*
* @property scrollToRow
* @type {Row}
* @default null
*/
scrollToRow: null,
_scrollToRow: null,
/**
* @property targetScrollOffset
* @type {Number}
* @default 0
* @private
*/
targetScrollOffset: 0,
/**
* @property currentScrollOffset
* @type {Number}
* @default 0
* @private
*/
currentScrollOffset: 0,
/**
* @property hasReachedTargetScrollOffset
* @type {Boolean}
* @default true
* @private
*/
hasReachedTargetScrollOffset: true,
/**
* Allows to customize the component used to render rows
*
* ```hbs
* <LightTable @table={{this.table}} as |t|}}
* <t.body @rowComponent={{component 'my-row'}} />
* </LightTable>
* ```
* @property rowComponent
* @type {Ember.Component}
* @default null
*/
rowComponent: null,
/**
* Allows to customize the component used to render spanned rows
*
* ```hbs
* <LightTable @table={{this.table}} as |t| >
* <t.body @spannedRowComponent={{component 'my-spanned-row'}} />
* </LightTable>
* ```
* @property spannedRowComponent
* @type {Ember.Component}
* @default null
*/
spannedRowComponent: null,
/**
* Allows to customize the component used to render infinite loader
*
* ```hbs
* <LightTable @table={{this.table}} as |t|>
* <t.body @infinityComponent={{component 'my-infinity'}} />
* </LightTable>
* ```
* @property infinityComponent
* @type {Ember.Component}
* @default null
*/
infinityComponent: null,
rows: readOnly('table.visibleRows'),
columns: readOnly('table.visibleColumns'),
colspan: readOnly('columns.length'),
/**
* fills the screen with row items until lt-infinity component has exited the viewport
* @property scheduleScrolledToBottom
*/
scheduleScrolledToBottom: action(function () {
if (this.isInViewport && this.onScrolledToBottom) {
/*
Continue scheduling onScrolledToBottom until no longer in viewport
*/
this._schedulerTimer = scheduleOnce(
'afterRender',
this,
this._debounceScrolledToBottom
);
}
}),
_prevSelectedIndex: -1,
init() {
this._super(...arguments);
/*
We can only set `useVirtualScrollbar` once all contextual components have
been initialized since fixedHeader and fixedFooter are set on t.head and t.foot
initialization.
*/
once(this, this._setupVirtualScrollbar);
},
destroy() {
this._super(...arguments);
this._cancelTimers();
},
_setupVirtualScrollbar() {
let { fixedHeader, fixedFooter } = this.sharedOptions;
this.set('useVirtualScrollbar', fixedHeader || fixedFooter);
},
onRowsChange: action(function () {
this._checkTargetOffsetTimer = scheduleOnce(
'afterRender',
this,
this.checkTargetScrollOffset
);
}),
setupScrollOffset: action(function (element) {
let { scrollTo, _scrollTo, scrollToRow, _scrollToRow } = this;
let targetScrollOffset = null;
this.setProperties({ _scrollTo: scrollTo, _scrollToRow: scrollToRow });
if (scrollTo !== _scrollTo) {
targetScrollOffset = Number.parseInt(scrollTo, 10);
if (Number.isNaN(targetScrollOffset)) {
targetScrollOffset = null;
}
this.setProperties({
targetScrollOffset,
hasReachedTargetScrollOffset: targetScrollOffset <= 0,
});
} else if (scrollToRow !== _scrollToRow) {
if (scrollToRow instanceof Row) {
let rowElement = element.querySelector(
`[data-row-id=${scrollToRow.get('rowId')}]`
);
if (rowElement instanceof Element) {
targetScrollOffset = rowElement.offsetTop;
}
}
this.setProperties({
targetScrollOffset,
hasReachedTargetScrollOffset: true,
});
}
}),
checkTargetScrollOffset() {
if (!this.hasReachedTargetScrollOffset) {
let targetScrollOffset = this.targetScrollOffset;
let currentScrollOffset = this.currentScrollOffset;
if (targetScrollOffset > currentScrollOffset) {
this.set('targetScrollOffset', null);
this._setTargetOffsetTimer = schedule('render', null, () => {
this.set('targetScrollOffset', targetScrollOffset);
});
} else {
this.set('hasReachedTargetScrollOffset', true);
}
}
},
toggleExpandedRow(row) {
let multiRowExpansion = this.multiRowExpansion;
let shouldExpand = !row.expanded;
if (multiRowExpansion) {
row.toggleProperty('expanded');
} else {
this.table.expandedRows.setEach('expanded', false);
row.set('expanded', shouldExpand);
}
},
/**
* @method _debounceScrolledToBottom
*/
_debounceScrolledToBottom(delay = 100) {
/*
This debounce is needed when there is not enough delay between onScrolledToBottom calls.
Without this debounce, all rows will be rendered causing immense performance problems
*/
this._debounceTimer = debounce(this, this.onScrolledToBottom, delay);
},
/**
* @method _cancelTimers
*/
_cancelTimers() {
cancel(this._checkTargetOffsetTimer);
cancel(this._setTargetOffsetTimer);
cancel(this._schedulerTimer);
cancel(this._debounceTimer);
},
// Noop for closure actions
onRowClick() {},
onRowDoubleClick() {},
onScroll() {},
firstVisibleChanged() {},
lastVisibleChanged() {},
firstReached() {},
lastReached() {},
/**
* lt-infinity action to determine if component is still in viewport
* @event enterViewport
*/
enterViewport: action(function () {
this.set('isInViewport', true);
}),
/**
* lt-infinity action to determine if component has exited the viewport
* @event exitViewport
*/
exitViewport: action(function () {
this.set('isInViewport', false);
}),
actions: {
/**
* onRowClick action. Handles selection, and row expansion.
* @event onRowClick
* @param {Row} row The row that was clicked
* @param {Event} event The click event
*/
onRowClick(row, e) {
let rows = this.table.rows;
let multiSelect = this.multiSelect;
let multiSelectRequiresKeyboard = this.multiSelectRequiresKeyboard;
let canSelect = this.canSelect;
let selectOnClick = this.selectOnClick;
let canExpand = this.canExpand;
let expandOnClick = this.expandOnClick;
let isSelected = row.get('selected');
let currIndex = rows.indexOf(row);
let prevIndex =
this._prevSelectedIndex === -1 ? currIndex : this._prevSelectedIndex;
this._prevSelectedIndex = currIndex;
let toggleExpandedRow = () => {
if (canExpand && expandOnClick) {
this.toggleExpandedRow(row);
}
};
if (canSelect) {
if (e.shiftKey && multiSelect) {
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 {
if (selectOnClick) {
this.table.selectedRows.setEach('selected', false);
row.set('selected', !isSelected);
}
toggleExpandedRow();
}
} else {
toggleExpandedRow();
}
this.onRowClick(...arguments);
},
/**
* onRowDoubleClick action.
* @event onRowDoubleClick
* @param {Row} row The row that was clicked
* @param {Event} event The click event
*/
onRowDoubleClick(/* row */) {
this.onRowDoubleClick(...arguments);
},
/**
* onScroll action - sent when user scrolls in the Y direction
*
* This only works when `useVirtualScrollbar` is `true`, i.e. when you are
* using fixed headers / footers.
*
* @event onScroll
* @param {Number} scrollOffset The scroll offset in px
* @param {Event} event The scroll event
*/
onScroll(scrollOffset /* , event */) {
this.set('currentScrollOffset', scrollOffset);
this.onScroll(...arguments);
},
firstVisibleChanged(item, index /* , key */) {
this.firstVisibleChanged(...arguments);
const estimateScrollOffset =
index * this.sharedOptions.estimatedRowHeight;
this.onScroll(estimateScrollOffset, null);
},
lastVisibleChanged(/* item, index, key */) {
this.lastVisibleChanged(...arguments);
},
firstReached(/* item, index, key */) {
this.firstReached(...arguments);
},
lastReached(/* item, index, key */) {
this.lastReached(...arguments);
this.onScrolledToBottom?.();
},
},
});
================================================
FILE: addon/components/lt-column-resizer.hbs
================================================
{{yield}}
================================================
FILE: addon/components/lt-column-resizer.js
================================================
import Component from '@ember/component';
import closest from 'ember-light-table/utils/closest';
const TOP_LEVEL_CLASS = '.ember-light-table';
export default Component.extend({
classNameBindings: [':lt-column-resizer', 'isResizing'],
column: null,
resizeOnDrag: false,
isResizing: false,
startWidth: null,
startX: null,
colElement() {
return this.element.parentNode;
},
didInsertElement() {
this._super(...arguments);
this.__mouseMove = this._mouseMove.bind(this);
this.__mouseUp = this._mouseUp.bind(this);
document.addEventListener('mousemove', this.__mouseMove);
document.addEventListener('mouseup', this.__mouseUp);
},
willDestroyElement() {
this._super(...arguments);
document.removeEventListener('mousemove', this.__mouseMove);
document.removeEventListener('mouseip', this.__mouseUp);
},
click(e) {
/*
Prevent click events from propagating (i.e. onColumnClick)
*/
e.preventDefault();
e.stopPropagation();
},
mouseDown(e) {
let column = this.colElement();
e.preventDefault();
e.stopPropagation();
this.setProperties({
isResizing: true,
startWidth: column.offsetWidth,
startX: e.pageX,
});
let topLevel = closest(this.element, TOP_LEVEL_CLASS);
topLevel.classList.add('is-resizing');
},
_mouseUp(e) {
if (this.isResizing) {
e.preventDefault();
e.stopPropagation();
let column = this.colElement();
let width = `${column.offsetWidth}px`;
this.set('isResizing', false);
this.set('column.width', width);
let topLevel = closest(this.element, TOP_LEVEL_CLASS);
topLevel.classList.remove('is-resizing');
this.onColumnResized(width);
}
},
_mouseMove(e) {
if (this.isResizing) {
e.preventDefault();
e.stopPropagation();
let resizeOnDrag = this.resizeOnDrag;
let minResizeWidth = this.column.minResizeWidth;
let { startX, startWidth } = this;
let width = `${Math.max(
startWidth + (e.pageX - startX),
minResizeWidth
)}px`;
let column = this.colElement();
let index = this.table.visibleColumns.indexOf(this.column) + 1;
let table = closest(this.element, TOP_LEVEL_CLASS);
column.style.width = width;
const headerScaffoldingCell = table.querySelector(
`thead td.lt-scaffolding:nth-child(${index})`
);
if (headerScaffoldingCell) {
headerScaffoldingCell.style.width = width;
}
const footerScaffoldingCell = table.querySelector(
`tfoot td.lt-scaffolding:nth-child(${index})`
);
if (footerScaffoldingCell) {
footerScaffoldingCell.style.width = width;
}
if (resizeOnDrag) {
let cols = table.querySelectorAll(`tbody td:nth-child(${index})`);
cols.forEach((col) => {
col.style.width = width;
});
}
}
},
// No-op for closure actions
onColumnResized() {},
});
================================================
FILE: addon/components/lt-foot.hbs
================================================
<EmberWormhole
@to={{concat this.tableId "_inline_foot"}}
@renderInPlace={{this.renderInPlace}}
>
<table class={{this.tableClassNames}}>
<tfoot class="lt-foot">
{{! Scaffolding is needed here to allow use of colspan in the footer }}
<LtScaffoldingRow @columns={{this.columns}} />
{{#if (has-block)}}
{{yield this.columns}}
{{else}}
<tr>
{{#each this.columns as |column|}}
{{component
(concat "light-table/columns/" column.type)
column=column
table=this.table
tableActions=this.tableActions
extra=this.extra
sortIcons=this.sortIcons
resizeOnDrag=this.resizeOnDrag
click=(action "onColumnClick" column)
doubleClick=(action "onColumnDoubleClick" column)
onColumnResized=(action "onColumnResized")
onColumnDrag=(action "onColumnDrag")
onColumnDrop=(action "onColumnDrop")
}}
{{/each}}
</tr>
{{/if}}
</tfoot>
</table>
</EmberWormhole>
================================================
FILE: addon/components/lt-foot.js
================================================
import Component from '@ember/component';
import TableHeaderMixin from 'ember-light-table/mixins/table-header';
/**
* @module Light Table
*/
/**
* ```hbs
* <LightTable @table={{this.table}} as |t|>
* <t.foot @onColumnClick={{this.sortByColumn}} />
* </LightTable>
* ```
* If you want to define your own tfoot, just declare the contextual component in a block.
*
* ```hbs
* <LightTable @table={{this.table}} as |t|>
* <t.foot @onColumnClick={{this.sortByColumn}} as |columns table|?
* {{#each columns as |column|}}
* {{!-- ... --}}
* {{/each}}
* </t.foot>
* </LightTable>
* ```
*
* will be empty
*
* @class t.foot
* @uses TableHeaderMixin
*/
export default Component.extend(TableHeaderMixin, {
classNames: ['lt-foot-wrap'],
table: null,
sharedOptions: null,
sharedOptionsFixedKey: 'fixedFooter',
});
================================================
FILE: addon/components/lt-head.hbs
================================================
<div class="lt-head-wrap">
<EmberWormhole
@to={{concat this.tableId "_inline_head"}}
@renderInPlace={{this.renderInPlace}}
>
<table class={{this.tableClassNames}}>
<thead class="lt-head">
{{#if (has-block)}}
{{yield this.columnGroups this.subColumns}}
{{else}}
{{! There is an issue where if there are more than 1 row and the first has a colspan,
the td's fail to hold their width. Creating a scaffolding will setup the table columns correctly
}}
{{#if this.subColumns.length}}
<LtScaffoldingRow @columns={{this.subColumns}} />
{{else}}
<LtScaffoldingRow @columns={{this.columnGroups}} />
{{/if}}
<tr>
{{#each this.columnGroups as |column|}}
{{component
(concat "light-table/columns/" column.type)
column=column
table=this.table
tableActions=this.tableActions
extra=this.extra
sortIcons=this.sortIcons
resizeOnDrag=this.resizeOnDrag
click=(action "onColumnClick" column)
doubleClick=(action "onColumnDoubleClick" column)
onColumnResized=(action "onColumnResized")
onColumnDrag=(action "onColumnDrag")
onColumnDrop=(action "onColumnDrop")
}}
{{/each}}
</tr>
<tr>
{{#each this.subColumns as |column|}}
{{component
(concat "light-table/columns/" column.type)
column=column
table=this.table
rowspan=1
classNames="lt-sub-column"
tableActions=this.tableActions
extra=this.extra
sortIcons=this.sortIcons
resizeOnDrag=this.resizeOnDrag
click=(action "onColumnClick" column)
doubleClick=(action "onColumnDoubleClick" column)
onColumnResized=(action "onColumnResized")
onColumnDrag=(action "onColumnDrag")
onColumnDrop=(action "onColumnDrop")
}}
{{/each}}
</tr>
{{/if}}
</thead>
</table>
</EmberWormhole>
</div>
================================================
FILE: addon/components/lt-head.js
================================================
import Component from '@ember/component';
import TableHeaderMixin from 'ember-light-table/mixins/table-header';
import classic from 'ember-classic-decorator';
/**
* @module Light Table
*/
/**
* ```hbs
* <LightTable @table={{this.table}} as |t|>
* {{t.head @onColumnClick=(action 'sortByColumn')}}
* </LightTable>
* ```
*
* If you want to define your own thead, just declare the contextual component in a block.
*
* ```hbs
* <LightTable @table={{this.table}} as |t|>
* <t.head @onColumnClick={{this.sortByColumn}} as |groups subColumns|>
* {{#each groups as |group|}}
* {{!-- ... --}}
* {{/each}}
* </t.head>
* </LightTable>
* ```
*
* If you dont have grouped columns, the yielded `groups` will be an array of all visibile columns and `subColumns`
* will be empty
*
* @class t.head
* @uses TableHeaderMixin
*/
@classic
export default class LtHeadComponent extends Component.extend(
TableHeaderMixin
) {
table = null;
sharedOptions = null;
sharedOptionsFixedKey = 'fixedHeader';
}
================================================
FILE: addon/components/lt-infinity.hbs
================================================
{{yield}}
================================================
FILE: addon/components/lt-infinity.js
================================================
import Component from '@ember/component';
import { inject as service } from '@ember/service';
export default Component.extend({
inViewport: service(),
classNames: ['lt-infinity'],
scrollableContent: null,
scrollBuffer: 50,
didInsertElement() {
this._super(...arguments);
const options = {
viewportSpy: true,
viewportTolerance: {
bottom: this.scrollBuffer,
},
scrollableArea: this.scrollableContent,
};
const { onEnter, onExit } = this.inViewport.watchElement(
this.element,
options
);
onEnter(this.didEnterViewport.bind(this));
onExit(this.didExitViewport.bind(this));
},
willDestroyElement() {
this._super(...arguments);
this.inViewport.stopWatching(this.element);
},
didEnterViewport() {
this.enterViewport();
},
didExitViewport() {
this.exitViewport();
},
});
================================================
FILE: addon/components/lt-row.hbs
================================================
{{#each this.columns as |column|}}
{{component
(concat 'light-table/cells/' column.cellType)
column=column
row=this.row
table=this.table
rawValue=(get this.row column.valuePath)
tableActions=this.tableActions
extra=this.extra
}}
{{/each}}
================================================
FILE: addon/components/lt-row.js
================================================
import Component from '@ember/component';
import { readOnly } from '@ember/object/computed';
export default Component.extend({
tagName: 'tr',
classNames: ['lt-row'],
classNameBindings: [
'isSelected',
'isExpanded',
'canExpand:is-expandable',
'canSelect:is-selectable',
'row.classNames',
],
attributeBindings: ['colspan', 'data-row-id'],
columns: null,
row: null,
tableActions: null,
extra: null,
canExpand: false,
canSelect: false,
colspan: 1,
isSelected: readOnly('row.selected'),
isExpanded: readOnly('row.expanded'),
});
================================================
FILE: addon/components/lt-scaffolding-row.hbs
================================================
{{#each this.columns as |column|}}
{{! template-lint-disable no-inline-styles }}
<td style={{html-safe (if column.width (concat "width: " column.width))}} class="lt-scaffolding"></td>
{{! template-lint-enable no-inline-styles }}
{{/each}}
================================================
FILE: addon/components/lt-scaffolding-row.js
================================================
import Component from '@ember/component';
export default Component.extend({
classNames: ['lt-scaffolding-row'],
tagName: 'tr',
});
================================================
FILE: addon/components/lt-scrollable.hbs
================================================
{{#if this.virtualScrollbar}}
<EmberScrollable
class="lt-scrollable"
@autoHide={{this.autoHide}}
@horizontal={{this.horizontal}}
@vertical={{this.vertical}}
@scrollToY={{this.scrollTo}}
@onScrollY={{this.onScrollY}} as |scrollbar|
>
{{yield scrollbar}}
</EmberScrollable>
{{else}}
{{yield}}
{{/if}}
================================================
FILE: addon/components/lt-scrollable.js
================================================
import Component from '@ember/component';
export default Component.extend({
tagName: '',
vertical: true,
horizontal: false,
});
================================================
FILE: addon/components/lt-spanned-row.hbs
================================================
{{#if this.visible}}
<tr class="lt-row {{html-safe this.classes}}">
<td colspan={{this.colspan}}>
{{yield this.yield}}
</td>
</tr>
{{/if}}
================================================
FILE: addon/components/lt-spanned-row.js
================================================
import Component from '@ember/component';
export default Component.extend({
colspan: 1,
tagName: '',
visible: true,
});
================================================
FILE: addon/helpers/compute.js
================================================
// https://github.com/DockYard/ember-composable-helpers/blob/master/addon/helpers/compute.js
import { helper } from '@ember/component/helper';
export function compute([action, ...params]) {
return action(...params);
}
export default helper(compute);
================================================
FILE: addon/helpers/html-safe.js
================================================
import { helper } from '@ember/component/helper';
import { htmlSafe as _htmlSafe } from '@ember/template';
export default helper(function htmlSafe(string /*, hash*/) {
return _htmlSafe(string);
});
================================================
FILE: addon/index.js
================================================
import Table from './classes/Table';
import Column from './classes/Column';
import Row from './classes/Row';
/**
* ## Installation
* ```shell
* ember install ember-light-table
* ```
*
* ## Looking for help?
* If it is a bug [please open an issue on GitHub](https://github.com/adopted-ember-addons/ember-light-table/issues).
*
* ## Usage
* There are two parts to this addon. The first is the [Table](../classes/Table.html) which you create with column definitions and rows, and the second is the component declaration.
*
* @module Usage
*/
/**
* ## Creating a Table Instance
*
* The first step is to create a table instance that will be used by the component to render
* the actual table structure. This same table instance can be used add, remove, and modify
* rows and columns. See the [table class documentation](../classes/Table.html) for more details.
*
* ```javascript
* import Table from 'ember-light-table';
*
* const table = Table.create({ columns: columns, rows: rows });
* ```
*
* Here is a more real-word example
*
* ```javascript
* // components/my-table.js
* import { computed } from '@ember/object';
* import Table from 'ember-light-table';
*
* export default Ember.Component.extend({
* model: null,
*
* 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'
* }];
* }),
*
* table: computed('model', function() {
* return Table.create({ columns: this.get('columns'), rows: this.get('model') });
* })
* });
* ```
*
* @module Usage
* @submodule Table Declaration
*/
/**
* The `light-table` component exposes 3 contextual component (head, body, and foot).
*
* ```hbs
* {{#light-table table as |t|}}
*
* {{t.head}}
*
* {{#t.body as |body|}}
* {{#body.expanded-row as |row|}}
* Hello <b>{{row.firstName}}</b>
* {{/body.expanded-row}}
*
* {{#if isLoading}}
* {{#body.loader}}
* Loading...
* {{/body.loader}}
* {{/if}}
*
* {{#if table.isEmpty}}
* {{#body.no-data}}
* No users found.
* {{/body.no-data}}
* {{/if}}
* {{/t.body}}
*
* {{t.foot}}
*
* {{/light-table}}
* ```
*
* Each of these contextual components have a wide array of options so it is advised to look
* through their documentation.
*
* @module Usage
* @submodule Component Declaration
*/
export default Table;
export { Table, Column, Row };
================================================
FILE: addon/mixins/draggable-column.js
================================================
import Mixin from '@ember/object/mixin';
import { computed } from '@ember/object';
import { cancel, next } from '@ember/runloop';
let sourceColumn;
export default Mixin.create({
classNameBindings: ['isDragging', 'isDragTarget', 'dragDirection'],
attributeBindings: ['isDraggable:draggable'],
isDragging: false,
isDragTarget: false,
dragDirection: computed(
'column',
'dragColumnGroup',
'isDragTarget',
function () {
if (this.isDragTarget) {
let columns = this.dragColumnGroup;
let targetIdx = columns.indexOf(this.column);
let sourceIdx = columns.indexOf(sourceColumn);
let direction = sourceIdx - targetIdx < 0 ? 'right' : 'left';
return `drag-${direction}`;
}
return '';
}
).readOnly(),
/**
* Array of Columns indicating where the column can be potentially dragged.
* If the column is part of a group (has a parent column), this will be all of the columns in that group,
* otherwise it's all of the columns in the table.
*
* @property dragColumnGroup
* @type Array
* @readonly
*/
dragColumnGroup: computed('column.parent', 'table.columns', function () {
let parent = this.column.get('parent');
return parent ? parent.get('subColumns') : this.table.columns;
}).readOnly(),
isDropTarget() {
let column = this.column;
/*
A column is a valid drop target only if its in the same group
*/
return (
sourceColumn &&
column.get('droppable') &&
column.get('parent') === sourceColumn.get('parent')
);
},
dragStart(e) {
this._super(...arguments);
let column = this.column;
/*
NOTE: IE requires setData type to be 'text'
*/
e.dataTransfer.setData('text', column.get('columnId'));
e.dataTransfer.effectAllowed = 'move';
sourceColumn = column;
this.set('isDragging', true);
this.onColumnDrag(sourceColumn, ...arguments);
/*
NOTE: This is a fix for Firefox to prevent the click event
from being triggered after a drop.
*/
this.__click__ = this.click;
this.click = undefined;
},
dragEnter(e) {
this._super(...arguments);
if (this.isDropTarget()) {
e.preventDefault();
this.set('isDragTarget', this.column !== sourceColumn);
}
},
dragOver(e) {
this._super(...arguments);
if (this.isDropTarget()) {
e.preventDefault();
/*
NOTE: dragLeave will be triggered by any child elements inside the
column. This code ensures the column being dragged over continues to be
identified as the current drop target
*/
if (!this.isDragTarget) {
this.set('isDragTarget', this.column !== sourceColumn);
}
}
},
dragLeave() {
this._super(...arguments);
this.set('isDragTarget', false);
},
dragEnd() {
this._super(...arguments);
this.setProperties({ isDragTarget: false, isDragging: false });
/*
If sourceColumn still references a column, it means that a successful
drop did not happen.
*/
if (sourceColumn) {
this.onColumnDrop(sourceColumn, false, ...arguments);
sourceColumn = null;
}
/*
Restore click event
*/
this._clickResetTimer = next(this, () => (this.click = this.__click__));
},
drop(e) {
this._super(...arguments);
let targetColumn = this.column;
if (targetColumn.droppable) {
let table = this.table;
let columns = this.dragColumnGroup;
let targetColumnIdx = columns.indexOf(targetColumn);
e.dataTransfer.dropEffect = 'move';
e.preventDefault();
e.stopPropagation();
columns.removeObject(sourceColumn);
columns.insertAt(targetColumnIdx, sourceColumn);
table.notifyPropertyChange('columns');
this.setProperties({ isDragTarget: false, isDragging: false });
this.onColumnDrop(sourceColumn, true, ...arguments);
sourceColumn = null;
}
},
destroy() {
this._super(...arguments);
cancel(this._clickResetTimer);
},
// Noop for passed actions
onColumnDrag() {},
onColumnDrop() {},
});
================================================
FILE: addon/mixins/table-header.js
================================================
import Mixin from '@ember/object/mixin';
import { computed, trySet } from '@ember/object';
import { oneWay, readOnly } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import { warn } from '@ember/debug';
import { inject as service } from '@ember/service';
import cssStyleify from 'ember-light-table/utils/css-styleify';
/**
* @module Light Table
*/
/**
* @class TableHeaderMixin
* @extends Ember.Mixin
* @private
*/
export default Mixin.create({
attributeBindings: ['style'],
scrollbarThickness: service(),
/**
* @property table
* @type {Table}
* @private
*/
table: null,
/**
* @property sharedOptions
* @type {Object}
* @private
*/
sharedOptions: null,
/**
* @property tableActions
* @type {Object}
*/
tableActions: null,
/**
* @property extra
* @type {Object}
*/
extra: null,
/**
* @property fixed
* @type {Boolean}
* @default false
*/
fixed: false,
/**
* @property sortOnClick
* @type {Boolean}
* @default true
*/
sortOnClick: true,
/**
* @property multiColumnSort
* @type {Boolean}
* @default false
*/
multiColumnSort: false,
/**
* Resize all cells in the column instead of just the header / footer
*
* @property resizeOnDrag
* @type {Boolean}
* @default false
*/
resizeOnDrag: false,
/**
* CSS classes to be applied to an `<i class="lt-sort-icon"></i>` tag that is
* inserted into the column's `<th>` element when the column is sortable but
* not yet sorted.
*
* For instance, if you have installed `ember-font-awesome` or include the
* `font-awesome` assets manually (e.g. via a CDN), you can set
* `iconSortable` to `'sort'`, which would yield this markup:
* `<i class="lt-sort-icon sort"></i>`
*
* @property iconSortable
* @type {String}
* @default ''
*/
iconSortable: '',
/**
* See `iconSortable`. CSS classes to apply to `<i class="lt-sort-icon"></i>`
* when the column is sorted ascending.
*
* @property iconAscending
* @type {String}
* @default ''
*/
iconAscending: '',
/**
* See `iconSortable`. CSS classes to apply to `<i class="lt-sort-icon"></i>`
* when the column is sorted descending.
*
* @property iconDescending
* @type {String}
* @default ''
*/
iconDescending: '',
/**
* Custom sorting component name to use instead of the default `<i class="lt-sort-icon"></i>` template.
* See `iconSortable`, `iconAsending`, or `iconDescending`.
* @property iconComponent
* @type {String}
* @default false
*/
iconComponent: null,
/**
* ID of main table component. Used to generate divs for ember-wormhole
* @type {String}
*/
tableId: null,
renderInPlace: oneWay('fixed'),
columnGroups: readOnly('table.visibleColumnGroups'),
subColumns: readOnly('table.visibleSubColumns'),
columns: readOnly('table.visibleColumns'),
sortIcons: computed(
'iconSortable',
'iconAscending',
'iconDescending',
'iconComponent',
function () {
return {
iconSortable: this.iconSortable,
iconAscending: this.iconAscending,
iconDescending: this.iconDescending,
iconComponent: this.iconComponent,
};
}
).readOnly(),
style: computed(
'scrollbarThickness.thickness',
'sharedOptions.occlusion',
function () {
if (this.sharedOptions?.occlusion) {
const scrollbarThickness = this.scrollbarThickness?.thickness;
return cssStyleify({ paddingRight: `${scrollbarThickness}px` });
}
return;
}
).readOnly(),
init() {
this._super(...arguments);
const fixed = this.fixed;
const sharedOptionsFixedPath = `sharedOptions.${this.sharedOptionsFixedKey}`;
trySet(this, sharedOptionsFixedPath, fixed);
const height = this.sharedOptions?.height;
warn(
'You did not set a `height` attribute for your table, but marked a header or footer to be fixed. This means that you have to set the table height via CSS. For more information please refer to: https://github.com/adopted-ember-addons/ember-light-table/issues/446',
!fixed || (fixed && !isEmpty(height)),
{ id: 'ember-light-table.height-attribute' }
);
},
actions: {
/**
* onColumnClick action. Handles column sorting.
*
* @event onColumnClick
* @param {Column} column The column that was clicked
* @param {Event} event The click event
*/
onColumnClick(column) {
if (column.sortable && this.sortOnClick) {
if (column.sorted) {
column.toggleProperty('ascending');
} else {
if (!this.multiColumnSort) {
this.table.sortedColumns.setEach('sorted', false);
}
column.set('sorted', true);
}
}
this.onColumnClick && this.onColumnClick(...arguments);
},
/**
* onColumnDoubleClick action.
*
* @event onColumnDoubleClick
* @param {Column} column The column that was clicked
* @param {Event} event The click event
*/
onColumnDoubleClick(/* column */) {
this.onColumnDoubleClick && this.onColumnDoubleClick(...arguments);
},
/**
* onColumnResized action.
*
* @event onColumnResized
* @param {Column} column The column that was resized
* @param {String} width The final width of the column
*/
onColumnResized(/* column, width */) {
this.onColumnResized && this.onColumnResized(...arguments);
},
/**
* onColumnDrag action.
*
* @event onColumnDrag
* @param {Column} column The column that is being dragged
*/
onColumnDrag(/* column */) {
this.onColumnDrag && this.onColumnDrag(...arguments);
},
/**
* onColumnDrop action.
*
* @event onColumnDrop
* @param {Column} column The column that was dropped
* @param {Boolean} isSuccess The column was successfully dropped and sorted
*/
onColumnDrop(/* column, isSuccess */) {
this.onColumnDrop && this.onColumnDrop(...arguments);
},
},
});
================================================
FILE: addon/styles/addon.css
================================================
.ember-light-table {
height: inherit;
overflow: auto;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.ember-light-table table {
table-layout: fixed;
border-collapse: collapse;
width: 100%;
box-sizing: border-box;
}
.ember-light-table .lt-scaffolding {
border: none;
padding-top: 0;
padding-bottom: 0;
height: 0;
margin-top: 0;
margin-bottom: 0;
visibility: hidden;
}
.ember-light-table .lt-head-wrap,
.ember-light-table .lt-foot-wrap {
overflow-y: auto;
overflow-x: hidden;
-webkit-box-flex: 0;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
}
.ember-light-table .lt-body-wrap {
overflow-y: hidden;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
}
.ember-light-table .lt-column {
position: relative;
}
.ember-light-table .lt-scrollable {
width: 100%;
-webkit-box-flex: 1;
-ms-flex: 1 1 auto;
flex: 1 1 auto;
}
.lt-infinity {
min-height: 1px;
}
.ember-light-table .lt-scrollable.vertical-collection {
overflow-y: auto;
}
.ember-light-table vertical-collection {
width: 100%;
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;
}
.ember-light-table .align-right {
text-align: right;
}
.ember-light-table .align-center {
text-align: center;
}
.ember-light-table .lt-column .lt-sort-icon {
float: right;
}
.ember-light-table .lt-column.is-draggable,
.ember-light-table .lt-column.is-sortable {
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.ember-light-table .lt-column.is-resizing {
pointer-events: none;
}
.ember-light-table.is-resizing {
cursor: col-resize;
}
.ember-light-table .lt-column .lt-column-resizer {
width: 5px;
cursor: col-resize;
height: 100%;
background: transparent;
position: absolute;
right: 0;
top: 0;
}
.ember-light-table .lt-row.is-expandable,
.ember-light-table .lt-row.is-selectable {
cursor: pointer;
}
================================================
FILE: addon/utils/closest.js
================================================
/**
* A polyfill for jQuery .closest() method
* @param { Object } el Dom element to start from
* @param { String } selector Selector to match
* @return { Object } The closest matching node or null
*/
const closest = (el, selector) => {
let parent;
while (el) {
parent = el.parentElement;
if (parent && parent.matches(selector)) {
return parent;
}
el = parent;
}
return;
};
export default closest;
================================================
FILE: addon/utils/css-styleify.js
================================================
import { dasherize } from '@ember/string';
import { htmlSafe } from '@ember/template';
import { isPresent } from '@ember/utils';
export default function cssStyleify(hash = {}) {
let styles = [];
Object.keys(hash).forEach((key) => {
let value = hash[key];
if (isPresent(value)) {
styles.push(`${dasherize(key)}: ${value}`);
}
});
return htmlSafe(styles.join('; '));
}
================================================
FILE: app/.gitkeep
================================================
================================================
FILE: app/components/light-table/cells/base.js
================================================
export { default } from 'ember-light-table/components/cells/base';
================================================
FILE: app/components/light-table/columns/base.js
================================================
export { default } from 'ember-light-table/components/columns/base';
================================================
FILE: app/components/light-table.js
================================================
export { default } from 'ember-light-table/components/light-table';
================================================
FILE: app/components/lt-body.js
================================================
export { default } from 'ember-light-table/components/lt-body';
================================================
FILE: app/components/lt-column-resizer.js
================================================
export { default } from 'ember-light-table/components/lt-column-resizer';
================================================
FILE: app/components/lt-foot.js
================================================
export { default } from 'ember-light-table/components/lt-foot';
================================================
FILE: app/components/lt-head.js
================================================
export { default } from 'ember-light-table/components/lt-head';
================================================
FILE: app/components/lt-infinity.js
================================================
export { default } from 'ember-light-table/components/lt-infinity';
================================================
FILE: app/components/lt-row.js
================================================
export { default } from 'ember-light-table/components/lt-row';
================================================
FILE: app/components/lt-scaffolding-row.js
================================================
export { default } from 'ember-light-table/components/lt-scaffolding-row';
================================================
FILE: app/components/lt-scrollable.js
================================================
export { default } from 'ember-light-table/components/lt-scrollable';
================================================
FILE: app/components/lt-spanned-row.js
================================================
export { default } from 'ember-light-table/components/lt-spanned-row';
================================================
FILE: app/helpers/compute.js
================================================
export { default, compute } from 'ember-light-table/helpers/compute';
================================================
FILE: app/helpers/html-safe.js
================================================
export { default, htmlSafe } from 'ember-light-table/helpers/html-safe';
================================================
FILE: blueprints/cell-type/files/app/components/light-table/cells/__name__.js
================================================
import Cell from 'ember-light-table/components/cells/base';
export default Cell.extend({
});
================================================
FILE: blueprints/cell-type/index.js
================================================
/* jshint node:true*/
module.exports = {
description: 'Generates a cell type and integration test',
};
================================================
FILE: blueprints/column-type/files/app/components/light-table/columns/__name__.js
================================================
import Column from 'ember-light-table/components/columns/base';
export default Column.extend({
});
================================================
FILE: blueprints/column-type/index.js
================================================
/* jshint node:true*/
module.exports = {
description: 'Generates a column type and integration test',
};
================================================
FILE: blueprints/ember-light-table/index.js
================================================
/* jshint node:true*/
module.exports = {
description: 'Install Ember Light Table dependencies',
normalizeEntityName() {},
beforeInstall() {
return this.addAddonToProject('ember-responsive');
},
};
================================================
FILE: ember-cli-build.js
================================================
'use strict';
const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
module.exports = function (defaults) {
let app = new EmberAddon(defaults, {
snippetSearchPaths: ['addon', 'tests/dummy/app'],
snippetPaths: ['snippets', 'tests/dummy/snippets'],
'ember-prism': {
components: ['markup-templating', 'handlebars', 'javascript'],
plugins: ['line-numbers'],
},
'ember-power-select': {
theme: 'bootstrap',
},
'ember-cli-babel': {
includePolyfill: true,
},
});
const { maybeEmbroider } = require('@embroider/test-setup');
return maybeEmbroider(app, {
skipBabel: [
{
package: 'qunit',
},
],
});
};
================================================
FILE: index.js
================================================
'use strict';
module.exports = {
name: require('./package').name,
};
================================================
FILE: package.json
================================================
{
"name": "ember-light-table",
"version": "3.0.0-beta.2",
"description": "Lightweight, component based table",
"keywords": [
"ember-addon",
"table"
],
"homepage": "https://github.com/adopted-ember-addons/ember-light-table",
"repository": {
"type": "git",
"url": "https://github.com/adopted-ember-addons/ember-light-table.git"
},
"license": "MIT",
"author": "",
"directories": {
"doc": "doc",
"test": "tests"
},
"scripts": {
"build": "ember build --environment=production",
"lint": "concurrently \"npm:lint:*(!fix)\" --names \"lint:\"",
"lint:fix": "concurrently \"npm:lint:*:fix\" --names \"fix:\"",
"lint:hbs": "ember-template-lint .",
"lint:hbs:fix": "ember-template-lint . --fix",
"lint:js": "eslint . --cache",
"lint:js:fix": "eslint . --fix",
"start": "ember serve",
"test": "concurrently \"npm:lint\" \"npm:test:*\" --names \"lint,test:\"",
"test:ember": "ember test",
"test:ember-compatibility": "ember try:each",
"changelog": "lerna-changelog"
},
"dependencies": {
"@embroider/util": "^1.9.0",
"@fortawesome/ember-fontawesome": "^0.2.2",
"@fortawesome/free-brands-svg-icons": "^5.15.2",
"@fortawesome/free-regular-svg-icons": "^5.15.2",
"@fortawesome/free-solid-svg-icons": "^5.15.2",
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"@html-next/vertical-collection": "^4.0.2",
"ember-classic-decorator": "^3.0.1",
"ember-cli-babel": "^7.26.11",
"ember-cli-htmlbars": "^6.1.1",
"ember-get-config": "^2.1.1",
"ember-in-viewport": "^4.1.0",
"ember-responsive": "^5.0.0",
"ember-scrollable": "rwwagner90/ember-scrollable#e00bd9b3719d5b0ea04870edb63713d10903990b",
"ember-truth-helpers": "^3.1.1",
"ember-wormhole": "^0.6.0"
},
"devDependencies": {
"@ember/jquery": "^2.0.0",
"@ember/optional-features": "^2.0.0",
"@ember/test-helpers": "^2.8.1",
"@embroider/test-setup": "^2.0.2",
"@faker-js/faker": "^7.6.0",
"babel-eslint": "^10.1.0",
"broccoli-asset-rev": "^3.0.0",
"concurrently": "^7.6.0",
"ember-auto-import": "^2.5.0",
"ember-cli": "~4.9.2",
"ember-cli-code-coverage": "^1.0.3",
"ember-cli-dependency-checker": "^3.3.1",
"ember-cli-github-pages": "^0.2.2",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-mirage": "^3.0.0-alpha.3",
"ember-cli-sass": "^11.0.1",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",
"ember-code-snippet": "^3.0.0",
"ember-composable-helpers": "^5.0.0",
"ember-concurrency": "^2.3.7",
"ember-data": "^3.16.0",
"ember-decorators": "^6.1.1",
"ember-load-initializers": "^2.1.2",
"ember-power-select": "^6.0.1",
"ember-prism": "^0.13.0",
"ember-qunit": "^6.0.0",
"ember-resolver": "^8.0.3",
"ember-source": "~4.9.1",
"ember-source-channel-url": "^3.0.0",
"ember-template-lint": "^5.2.0",
"ember-try": "^2.0.0",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-ember": "^11.2.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-qunit": "^7.3.4",
"lerna-changelog": "^1.0.1",
"loader.js": "^4.7.0",
"miragejs": "^0.1.45",
"prettier": "^2.8.1",
"qunit": "^2.19.3",
"qunit-dom": "^2.0.0",
"release-it": "^15.6.0",
"release-it-lerna-changelog": "^5.0.0",
"sass": "^1.57.1",
"webpack": "^5.75.0"
},
"peerDependencies": {
"ember-source": "^3.28.0 || ^4.0.0"
},
"engines": {
"node": "14.* || 16.* || >= 18"
},
"publishConfig": {
"registry": "https://registry.npmjs.org"
},
"ember": {
"edition": "octane"
},
"ember-addon": {
"configPath": "tests/dummy/config",
"demoURL": "http://adopted-ember-addons.github.io/ember-light-table",
"versionCompatibility": {
"ember": ">=3.24.0 <4.0.0"
}
},
"release-it": {
"plugins": {
"release-it-lerna-changelog": {
"infile": "CHANGELOG.md",
"launchEditor": true
}
},
"git": {
"tagName": "v${version}"
},
"github": {
"release": true,
"tokenRef": "GITHUB_AUTH"
}
},
"volta": {
"node": "14.20.0",
"yarn": "1.22.17"
}
}
================================================
FILE: testem.js
================================================
'use strict';
module.exports = {
test_page: 'tests/index.html?hidepassed',
disable_watching: true,
launch_in_ci: ['Chrome'],
launch_in_dev: ['Chrome'],
browser_start_timeout: 120,
browser_args: {
Chrome: {
ci: [
// --no-sandbox is needed when running Chrome inside a container
process.env.CI ? '--no-sandbox' : null,
'--headless',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--mute-audio',
'--remote-debugging-port=0',
'--window-size=1440,900',
].filter(Boolean),
},
},
};
================================================
FILE: tests/dummy/app/adapters/application.js
================================================
import JSONAPIAdapter from '@ember-data/adapter/json-api';
import ENV from '../config/environment';
export default class Application extends JSONAPIAdapter {
namespace = `${ENV.rootURL}api`;
}
================================================
FILE: tests/dummy/app/app.js
================================================
import Application from '@ember/application';
import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers';
import config from 'dummy/config/environment';
export default class App extends Application {
modulePrefix = config.modulePrefix;
podModulePrefix = config.podModulePrefix;
Resolver = Resolver;
}
loadInitializers(App, config.modulePrefix);
================================================
FILE: tests/dummy/app/breakpoints.js
================================================
/* eslint-disable key-spacing */
export default {
mobile: '(max-width: 768px)',
tablet: '(min-width: 769px) and (max-width: 992px)',
desktop: '(min-width: 993px) and (max-width: 1200px)',
jumbo: '(min-width: 1201px)',
};
================================================
FILE: tests/dummy/app/components/.gitkeep
================================================
================================================
FILE: tests/dummy/app/components/base-table.js
================================================
// BEGIN-SNIPPET base-table
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { isEmpty } from '@ember/utils';
import { inject as service } from '@ember/service';
import Table from 'ember-light-table';
import { restartableTask } from 'ember-concurrency';
import { tracked } from '@glimmer/tracking';
export default class BaseTable extends Component {
@service store;
@tracked canLoadMore = true;
@tracked dir = 'asc';
@tracked limit = 10;
@tracked meta = null;
@tracked model = [];
@tracked page = 0;
@tracked sort = 'firstName';
@tracked table;
constructor() {
super(...arguments);
this.model = this.args.model;
const table = Table.create({
columns: this.columns,
rows: this.model,
});
const sortColumn = table.get('allColumns').findBy('valuePath', this.sort);
// Setup initial sort column
if (sortColumn) {
sortColumn.set('sorted', true);
}
this.table = table;
}
get isLoading() {
return this.fetchRecords.isRunning;
}
@restartableTask *fetchRecords() {
const records = yield this.store.query('user', {
page: this.page,
limit: this.limit,
sort: this.sort,
dir: this.dir,
});
const recordsArray = records.toArray();
this.model.push(...recordsArray);
this.table.addRows(recordsArray);
this.meta = records.meta;
this.canLoadMore = !isEmpty(records);
}
@action
onScrolledToBottom() {
if (this.canLoadMore) {
this.page = this.page + 1;
this.fetchRecords.perform();
}
}
@action
onColumnClick(column) {
if (column.sorted) {
this.dir = column.ascending ? 'asc' : 'desc';
this.sort = column.valuePath;
this.canLoadMore = true;
this.page = 0;
this.model = [];
this.table.setRows(this.model);
}
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/code-panel.hbs
================================================
<div
class="panel-group"
id={{concat this.elementId "-code-panel"}}
role="tablist"
>
<div class="panel panel-default">
<div class="panel-heading">
<a
role="button"
data-toggle="collapse"
data-parent="#{{concat this.elementId "-code-panel"}}"
href="#{{concat this.elementId "-code-snippet"}}"
>
<h4 class="panel-title">
{{@title}}
<span class="code-icon pull-right">
<FaIcon @icon="code" />
</span>
</h4>
</a>
</div>
<div
id={{concat this.elementId "-code-snippet"}}
class="panel-collapse {{if this.collapse "collapse"}}"
role="tabpanel"
>
<div class="panel-body code-snippet">
<ul class="nav nav-tabs" role="tablist">
{{#each @snippets as |snippet index|}}
<li class={{if (eq index 0) "active"}}>
<a
href="#{{classify snippet}}"
aria-controls={{classify snippet}}
role="tab"
data-toggle="tab"
>
{{snippet}}
</a>
</li>
{{/each}}
</ul>
<div class="tab-content">
{{#each @snippets as |snippet index|}}
<div
role="tabpanel"
class="tab-pane fade {{if (eq index 0) "in active"}}"
id={{classify snippet}}
>
<CodeSnippet @name={{snippet}} />
</div>
{{/each}}
</div>
</div>
</div>
<div class="panel-body table-container">
{{yield}}
</div>
</div>
</div>
================================================
FILE: tests/dummy/app/components/code-panel.js
================================================
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { guidFor } from '@ember/object/internals';
export default class CodePanel extends Component {
@tracked collapse = true;
elementId = guidFor(this);
}
================================================
FILE: tests/dummy/app/components/code-snippet.hbs
================================================
{{! https://github.com/ef4/ember-code-snippet/blob/master/CHANGELOG.md#300}}
{{#let (get-code-snippet @name) as |snippet|}}
{{! CodeBlock is provided by ember-prism }}
<CodeBlock
@code={{snippet.source}}
@language={{snippet.language}}
class='line-numbers'
/>
{{/let}}
================================================
FILE: tests/dummy/app/components/colored-row.js
================================================
// BEGIN-SNIPPET colored-row
import classic from 'ember-classic-decorator';
import { classNames, attributeBindings } from '@ember-decorators/component';
import { htmlSafe } from '@ember/template';
import Row from 'ember-light-table/components/lt-row';
@classic
@classNames('colored-row')
@attributeBindings('style')
export default class ColoredRow extends Row {
get style() {
return htmlSafe(`background-color: ${this.row.get('color')};`);
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/columns/draggable-table.hbs
================================================
{{! BEGIN-SNIPPET draggable-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
<t.foot @fixed={{true}} as |columns|>
<tr>
<td class="align-center" colspan={{columns.length}}>
Drag and drop a column onto another to reorder the columns
</td>
</tr>
</t.foot>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/columns/draggable-table.js
================================================
// BEGIN-SNIPPET draggable-table
import BaseTable from '../base-table';
export default class DraggableTable extends BaseTable {
get columns() {
return [
{
label: 'User Details',
sortable: false,
align: 'center',
draggable: true,
subColumns: [
{
label: 'Avatar',
valuePath: 'avatar',
width: '60px',
sortable: false,
align: 'center',
draggable: true,
cellComponent: 'user-avatar',
},
{
label: 'First',
valuePath: 'firstName',
width: '150px',
draggable: true,
},
{
label: 'Last',
valuePath: 'lastName',
width: '150px',
draggable: true,
},
],
},
{
label: 'Contact Information',
sortable: false,
align: 'center',
draggable: true,
subColumns: [
{
label: 'Address',
valuePath: 'address',
draggable: true,
},
{
label: 'State',
valuePath: 'state',
draggable: true,
},
{
label: 'Country',
valuePath: 'country',
draggable: true,
},
],
},
];
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/columns/grouped-table.hbs
================================================
{{! BEGIN-SNIPPET grouped-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/columns/grouped-table.js
================================================
// BEGIN-SNIPPET grouped-table
import BaseTable from '../base-table';
export default class GroupedTable extends BaseTable {
get columns() {
return [
{
label: 'User Details',
sortable: false,
align: 'center',
subColumns: [
{
label: 'Avatar',
valuePath: 'avatar',
width: '60px',
sortable: false,
cellComponent: 'user-avatar',
},
{
label: 'First',
valuePath: 'firstName',
width: '150px',
},
{
label: 'Last',
valuePath: 'lastName',
width: '150px',
},
],
},
{
label: 'Contact Information',
sortable: false,
align: 'center',
subColumns: [
{
label: 'Address',
valuePath: 'address',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
valuePath: 'country',
},
],
},
];
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/columns/resizable-table.hbs
================================================
{{! BEGIN-SNIPPET resizable-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@resizeOnDrag={{true}}
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
<t.foot
@onColumnClick={{this.onColumnClick}}
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@resizeOnDrag={{true}}
@fixed={{true}}
/>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/columns/resizable-table.js
================================================
// BEGIN-SNIPPET resizable-table
import BaseTable from '../base-table';
export default class ResizableTable extends BaseTable {
get columns() {
return [
{
label: 'User Details',
sortable: false,
align: 'center',
subColumns: [
{
label: 'Avatar',
valuePath: 'avatar',
width: '60px',
sortable: false,
cellComponent: 'user-avatar',
},
{
label: 'First',
resizable: true,
valuePath: 'firstName',
width: '150px',
minResizeWidth: 75,
},
{
label: 'Last',
resizable: true,
valuePath: 'lastName',
width: '150px',
minResizeWidth: 75,
},
],
},
{
label: 'Contact Information',
sortable: false,
align: 'center',
subColumns: [
{
label: 'Address',
resizable: true,
valuePath: 'address',
minResizeWidth: 100,
},
{
label: 'State',
resizable: true,
valuePath: 'state',
minResizeWidth: 100,
},
{
label: 'Country',
resizable: true,
valuePath: 'country',
minResizeWidth: 100,
},
],
},
];
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/cookbook/client-side-table.hbs
================================================
{{! BEGIN-SNIPPET client-side-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
{{!
In order for `sort-up` and `sort-down` icons to work,
you need to have ember-font-awesome installed or manually include
the font-awesome assets, e.g. via a CDN.
}}
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body @canSelect={{false}} as |body|>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
<t.foot @fixed={{true}} as |columns|>
<tr>
<td class="row" colspan={{columns.length}}>
<div class="col-md-6">
<PowerSelect
@selected={{this.selectedFilter}}
@options={{this.possibleFilters}}
@onChange={{
pipe-action (fn (mut this.selectedFilter)) this.onSearchChange
}}
@placeholder="Select filter column..."
class="form-control"
name="scrollToRow" as |option|
>
{{option.label}}
</PowerSelect>
</div>
<div class="col-md-6">
<Input
@value={{this.query}}
placeholder="Search..."
class="form-control"
{{on "keydown" (pipe-action this.updateQuery this.onSearchChange)}}
/>
</div>
</td>
</tr>
</t.foot>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/cookbook/client-side-table.js
================================================
// BEGIN-SNIPPET client-side-table
import BaseTable from '../base-table';
import { action } from '@ember/object';
import { restartableTask, timeout } from 'ember-concurrency';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
export default class PaginatedTable extends BaseTable {
@service store;
query = '';
@tracked meta;
// Filter Input
@tracked selectedFilter = this.possibleFilters.firstObject;
get sortedModel() {
if (this.dir === 'asc') return this.model.sortBy(this.sort);
else return this.model.sortBy(this.sort).reverse();
}
get isLoading() {
return this.fetchRecords?.isRunning || this.setRows?.isRunning;
}
get possibleFilters() {
return this.table.columns.filterBy('sortable', true);
}
get columns() {
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',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
valuePath: 'country',
},
];
}
constructor() {
super(...arguments);
this.fetchRecords.perform();
}
@restartableTask *fetchRecords() {
const records = yield this.store.query('user', { page: 1, limit: 100 });
const recordsArray = records.toArray();
this.model.push(...recordsArray);
this.meta = records.meta;
yield this.filterAndSortModel.perform();
}
@restartableTask *setRows(rows) {
this.table.setRows([]);
yield timeout(100); // Allows isLoading state to be shown
this.table.setRows(rows);
}
@restartableTask *filterAndSortModel(debounceMs = 200) {
yield timeout(debounceMs); // debounce
const query = this.query;
const model = this.sortedModel;
let result = model;
if (query !== '' && this.selectedFilter !== undefined) {
const { valuePath } = this.selectedFilter;
result = model.filter((m) => {
return m.get(valuePath).toLowerCase().includes(query.toLowerCase());
});
}
yield this.setRows.perform(result);
}
@action
onColumnClick(column) {
if (column.sorted) {
this.dir = column.ascending ? 'asc' : 'desc';
this.sort = column.valuePath;
this.filterAndSortModel.perform(100);
}
}
@action
updateQuery(event) {
this.query = event.target.value;
}
@action
onSearchChange() {
this.filterAndSortModel.perform();
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/cookbook/custom-row-table.hbs
================================================
{{! BEGIN-SNIPPET custom-row-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
{{!
In order for `sort-up` and `sort-down` icons to work,
you need to have ember-font-awesome installed or manually include
the font-awesome assets, e.g. via a CDN.
}}
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}}
@rowComponent={{component "colored-row"}} as |body|
>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/cookbook/custom-row-table.js
================================================
// BEGIN-SNIPPET custom-row-table
import BaseTable from '../base-table';
export default class CustomRowTable extends BaseTable {
get columns() {
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',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
valuePath: 'country',
},
];
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/cookbook/custom-sort-icon-table.hbs
================================================
{{!-- BEGIN-SNIPPET custom-sort-icon-table --}}
<LightTable @table={{this.table}} @height="65vh" as |t|>
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="unfold_more"
@iconAscending="keyboard_arrow_up"
@iconDescending="keyboard_arrow_down"
@iconComponent="materialize-icon"
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}}
as |body|>
{{#if this.isLoading}}
<body.loader>
<TableLoader/>
</body.loader>
{{/if}}
</t.body>
</LightTable>
{{!-- END-SNIPPET --}}
================================================
FILE: tests/dummy/app/components/cookbook/custom-sort-icon-table.js
================================================
// BEGIN-SNIPPET custom-sort-icon-table
import BaseTable from '../base-table';
export default class CustomSortIconTable extends BaseTable {
get columns() {
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',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
valuePath: 'country',
},
];
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/cookbook/horizontal-scrolling-table.hbs
================================================
{{! BEGIN-SNIPPET horizontal-scrolling-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
{{!
In order for `sort-up` and `sort-down` icons to work,
you need to have ember-font-awesome installed or manually include
the font-awesome assets, e.g. via a CDN.
}}
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/cookbook/horizontal-scrolling-table.js
================================================
// BEGIN-SNIPPET horizontal-scrolling-table
import BaseTable from '../base-table';
export default class HorizontalScrollingTable extends BaseTable {
get columns() {
return [
{
label: 'Avatar',
valuePath: 'avatar',
width: '60px',
sortable: false,
cellComponent: 'user-avatar',
},
{
label: 'First Name',
valuePath: 'firstName',
width: '350px',
},
{
label: 'Last Name',
valuePath: 'lastName',
width: '350px',
},
{
label: 'Address',
valuePath: 'address',
width: '350px',
},
{
label: 'State',
valuePath: 'state',
width: '350px',
},
{
label: 'Country',
valuePath: 'country',
width: '350px',
},
];
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/cookbook/index-list.hbs
================================================
<dl>
<dt><LinkTo @route="cookbook.client-side">Client Side Search & Sort</LinkTo></dt>
<dd>
<p>Fully searchable and sortable tables, client side.</p>
</dd>
<dt><LinkTo @route="cookbook.custom-row">Custom Row Component</LinkTo></dt>
<dd>
<p>Need more than the default ELT rows? Simply create your own rowComponent.</p>
</dd>
<dt><LinkTo @route="cookbook.custom-sort-icon">Custom Sort Icon</LinkTo></dt>
<dd>
<p>Not a fan of fa-icons? Easily change it to any font you like using the table's iconComponent.</p>
</dd>
<dt><LinkTo @route="cookbook.horizontal-scrolling">Horizontal Scrolling</LinkTo></dt>
<dd>
<p>Horizontal scrolling automatically enabled if the combined width of all columns exceeds table width.</p>
</dd>
<dt><LinkTo @route="cookbook.occlusion-rendering">Occlusion Rendering</LinkTo></dt>
<dd>
<p>The holy grail of tables. Intelligent row offloading to scroll huge lists forever, without performance degradation.</p>
</dd>
<dt><LinkTo @route="cookbook.pagination">Pagination</LinkTo></dt>
<dd>
<p>Feel free to add any pagination to your table's footer.</p>
</dd>
<dt><LinkTo @route="cookbook.table-actions">Table Actions</LinkTo></dt>
<dd>
<p>Interact with your rows and cells the Ember way: "Data Down, Actions Up" (DDAU)</p>
</dd>
</dl>
================================================
FILE: tests/dummy/app/components/cookbook/occluded-table.hbs
================================================
{{!-- BEGIN-SNIPPET occluded-table --}}
<LightTable
@table={{this.table}}
@height="65vh"
@occlusion={{true}}
@estimatedRowHeight={{50}}
as |t|>
{{!--
In order for `sort-up` and `sort-down` icons to work,
you need to have ember-font-awesome installed or manually include
the font-awesome assets, e.g. via a CDN.
--}}
<t.head @fixed={{true}}/>
<t.body
@canSelect={{false}}
@scrollBuffer={{200}}
@onScrolledToBottom={{this.onScrolledToBottom}}
as |body|>
{{#if this.isLoading}}
<body.loader>
<TableLoader/>
</body.loader>
{{/if}}
</t.body>
<t.foot @fixed={{true}}/>
</LightTable>
{{!-- END-SNIPPET --}}
================================================
FILE: tests/dummy/app/components/cookbook/occluded-table.js
================================================
// BEGIN-SNIPPET occluded-table
import BaseTable from '../base-table';
export default class OccludedTable extends BaseTable {
limit = 100;
get columns() {
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',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
valuePath: 'country',
},
];
}
constructor() {
super(...arguments);
this.page = 1;
this.fetchRecords.perform();
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/cookbook/paginated-table.hbs
================================================
{{! BEGIN-SNIPPET paginated-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
{{!
In order for `sort-up` and `sort-down` icons to work,
you need to have ember-font-awesome installed or manually include
the font-awesome assets, e.g. via a CDN.
}}
<t.head
@onColumnClick={{pipe this.onColumnClick (fn this.setPage 1)}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body @canSelect={{false}} as |body|>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
{{#if this.meta}}
<t.foot @fixed={{true}} as |columns|>
<tr>
<td class="align-center" colspan={{columns.length}}>
<ul class="pagination pagination-sm">
<li class={{if (eq this.page 1) "disabled"}}>
<button
type="button"
aria-label="Previous"
{{on "click" (fn this.setPage (dec this.page))}}
>
<span aria-hidden="true">
«
</span>
</button>
</li>
{{#each (range 1 this.meta.totalPages true) as |p|}}
<li class={{if (eq p this.page) "active"}}>
<button type="button" {{on "click" (fn this.setPage p)}}>
{{p}}
</button>
</li>
{{/each}}
<li class={{if (eq this.page this.meta.totalPages) "disabled"}}>
<button
type="button"
aria-label="Next"
{{on "click" (fn this.setPage (inc this.page))}}
>
<span aria-hidden="true">
»
</span>
</button>
</li>
</ul>
</td>
</tr>
</t.foot>
{{/if}}
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/cookbook/paginated-table.js
================================================
// BEGIN-SNIPPET paginated-table
import BaseTable from '../base-table';
import { action } from '@ember/object';
export default class PaginatedTable extends BaseTable {
limit = 12;
get columns() {
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',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
valuePath: 'country',
},
];
}
constructor() {
super(...arguments);
this.setPage(1);
}
@action
setPage(page) {
const totalPages = this.meta?.totalPages;
const currPage = this.page;
if (page < 1 || page > totalPages || page === currPage) {
return;
}
this.page = page;
this.model = [];
this.table.setRows(this.model);
this.fetchRecords.perform();
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/cookbook/table-actions-table.hbs
================================================
{{! BEGIN-SNIPPET table-actions-table }}
<LightTable
@table={{this.table}}
@height="65vh"
@tableActions={{
hash deleteUser=this.deleteUser notifyUser=this.notifyUser
}} as |t|
>
{{!
In order for `sort-up` and `sort-down` icons to work,
you need to have ember-font-awesome installed or manually include
the font-awesome assets, e.g. via a CDN.
}}
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/cookbook/table-actions-table.js
================================================
// BEGIN-SNIPPET table-actions-table
import BaseTable from '../base-table';
import { action } from '@ember/object';
export default class TableActionsTable extends BaseTable {
get columns() {
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',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
valuePath: 'country',
},
{
label: 'Actions',
width: '100px',
sortable: false,
cellComponent: 'user-actions',
},
];
}
@action
deleteUser(row) {
const confirmed = window.confirm(
`Are you sure you want to delete ${row.get('firstName')} ${row.get(
'lastName'
)}?`
);
if (confirmed) {
this.table.removeRow(row);
row.get('content').deleteRecord();
}
}
@action
notifyUser(row) {
window.alert(
`${row.get('firstName')} ${row.get('lastName')} has been notified.`
);
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/expanded-row.hbs
================================================
{{!-- BEGIN-SNIPPET expanded-row --}}
<div class="row">
<div class="col-md-2">
<img src={{@row.avatar}} class="user-avatar" alt="avatar">
</div>
<div class="col-md-8">
<p>{{@row.bio}}</p>
<div class="user-actions">
<a href="mailto:{{@row.email}}"><FaIcon @icon="envelope"/></a>
<a href="#"><FaIcon @icon="facebook" @prefix="fab"/></a>
<a href="#"><FaIcon @icon="twitter" @prefix="fab" /></a>
</div>
</div>
</div>
{{!-- END-SNIPPET --}}
================================================
FILE: tests/dummy/app/components/fa-icon-wrapper.hbs
================================================
<FaIcon @icon={{get @sortIcons @sortIconProperty}}/>
================================================
FILE: tests/dummy/app/components/materialize-icon.hbs
================================================
{{!-- BEGIN-SNIPPET materialize-icon --}}
<span>
<i class="lt-sort-icon material-icons">{{get @sortIcons @sortIconProperty}}</i>
</span>
{{!-- END-SNIPPET --}}
================================================
FILE: tests/dummy/app/components/no-data.hbs
================================================
{{!-- BEGIN-SNIPPET no-data --}}
<div class="row">
<div class="col-md-2 col-md-offset-4">
<img src="images/tomster.png" alt="" role="none">
</div>
<div class="col-md-4">
<h2>Hi there!</h2>
<p>Uhh... Looks like you've delete all our users</p>
<p>Lets see, have you tried turning it off and on?</p>
</div>
</div>
{{!-- END-SNIPPET --}}
================================================
FILE: tests/dummy/app/components/responsive-expanded-row.hbs
================================================
{{!-- BEGIN-SNIPPET responsive-expanded-row --}}
<div class="row">
<dl class="dl-horizontal">
{{#each @table.responsiveHiddenColumns as |column|}}
<dt>{{column.label}}:</dt>
<dd>{{get @row column.valuePath}}</dd>
{{/each}}
</dl>
</div>
{{!-- END-SNIPPET --}}
================================================
FILE: tests/dummy/app/components/responsive-table.hbs
================================================
{{! BEGIN-SNIPPET responsive-table }}
<LightTable
@table={{this.table}}
@height="65vh"
@responsive={{true}}
@onAfterResponsiveChange={{this.onAfterResponsiveChange}} as |t|
>
{{!
In order for `sort-up` and `sort-down` icons to work,
you need to have ember-font-awesome installed or manually include
the font-awesome assets, e.g. via a CDN.
}}
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@canSelect={{false}}
@expandOnClick={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
<body.expanded-row as |row|>
<ResponsiveExpandedRow @table={{this.table}} @row={{row}} />
</body.expanded-row>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
<t.foot @fixed={{true}} as |columns|>
<tr>
<td class="align-center" colspan={{columns.length}}>
<FaIcon aria-hidden="true" class="pull-left" @icon="chevron-left" />
Resize your browser to check out the responsive behavior
<FaIcon aria-hidden="true" class="pull-right" @icon="chevron-right" />
</td>
</tr>
</t.foot>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/responsive-table.js
================================================
// BEGIN-SNIPPET responsive-table
import BaseTable from './base-table';
import { action } from '@ember/object';
export default class ResponsiveTable extends BaseTable {
get columns() {
return [
{
width: '40px',
sortable: false,
cellComponent: 'row-toggle',
breakpoints: ['mobile', 'tablet', 'desktop'],
},
{
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',
breakpoints: ['tablet', 'desktop', 'jumbo'],
},
{
label: 'Address',
valuePath: 'address',
breakpoints: ['tablet', 'desktop', 'jumbo'],
},
{
label: 'State',
valuePath: 'state',
breakpoints: ['desktop', 'jumbo'],
},
{
label: 'Country',
valuePath: 'country',
breakpoints: ['jumbo'],
},
];
}
@action
onAfterResponsiveChange(matches) {
if (matches.indexOf('jumbo') > -1) {
this.table.expandedRows.setEach('expanded', false);
}
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/row-toggle.hbs
================================================
{{! BEGIN-SNIPPET row-toggle }}
<button
class="row-toggle"
type="button"
{{on "click" (fn (toggle "expanded" @row))}}
>
<i>
{{#if (get @row "expanded")}}
<FaIcon @icon="chevron-down" />
{{else}}
<FaIcon @icon="chevron-right" />
{{/if}}
</i>
</button>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/rows/expandable-table.hbs
================================================
{{! BEGIN-SNIPPET expandable-table }}
<LightTable @table={{this.table}} @height="65vh" as |t|>
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@canExpand={{true}}
@multiRowExpansion={{false}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
<body.expanded-row as |row|>
<ExpandedRow @row={{row}} />
</body.expanded-row>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
</t.body>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/rows/expandable-table.js
================================================
// BEGIN-SNIPPET expandable-table
import BaseTable from '../base-table';
export default class ExpandableTable extends BaseTable {
get columns() {
return [
{
label: 'First Name',
valuePath: 'firstName',
},
{
label: 'Last Name',
valuePath: 'lastName',
},
];
}
}
// END-SNIPPET
================================================
FILE: tests/dummy/app/components/rows/selectable-table.hbs
================================================
{{! BEGIN-SNIPPET selectable-table }}
<div class="table-actions">
{{#if this.hasSelection}}
<div
class="table-action"
title="Deselect all"
role="button"
{{on "click" this.deselectAll}}
>
<FaIcon @icon="check-square" @prefix="far" />
</div>
<div
class="table-action delete"
title="Delete selected"
role="button"
{{on "click" this.deleteAll}}
>
<FaIcon @icon="trash-alt" @prefix="far" />
</div>
{{else}}
<div
class="table-action"
title="Select all"
role="button"
{{on "click" this.selectAll}}
>
<FaIcon @icon="square" @prefix="far" />
</div>
{{/if}}
</div>
<LightTable @table={{this.table}} @height="65vh" as |t|>
<t.head
@onColumnClick={{this.onColumnClick}}
@iconSortable="sort"
@iconAscending="sort-up"
@iconDescending="sort-down"
@iconComponent="fa-icon-wrapper"
@fixed={{true}}
/>
<t.body
@multiSelect={{true}}
@onScrolledToBottom={{this.onScrolledToBottom}} as |body|
>
{{#if this.isLoading}}
<body.loader>
<TableLoader />
</body.loader>
{{/if}}
{{#if (and (not this.isLoading) this.table.isEmpty)}}
<body.no-data>
<NoData />
</body.no-data>
{{/if}}
</t.body>
</LightTable>
{{! END-SNIPPET }}
================================================
FILE: tests/dummy/app/components/rows/selectable-table.js
================================================
// BEGIN-SNIPPET selectable-table
import BaseTable from '../base-table';
import { action } from '@ember/object';
export default class ExpandableTable extends BaseTable {
get hasSelection() {
return this.table.selectedRows;
}
get columns() {
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',
},
{
label: 'State',
valuePath: 'state',
},
{
label: 'Country',
gitextract_3izqe97e/ ├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .github/ │ └── workflows/ │ └── ci.yml ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc.js ├── .template-lintrc.js ├── .tool-versions ├── .watchmanconfig ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── RELEASE.md ├── addon/ │ ├── -private/ │ │ └── global-options.js │ ├── .gitkeep │ ├── classes/ │ │ ├── Column.js │ │ ├── Row.js │ │ └── Table.js │ ├── components/ │ │ ├── cells/ │ │ │ ├── base.hbs │ │ │ └── base.js │ │ ├── columns/ │ │ │ ├── base.hbs │ │ │ └── base.js │ │ ├── light-table.hbs │ │ ├── light-table.js │ │ ├── lt-body.hbs │ │ ├── lt-body.js │ │ ├── lt-column-resizer.hbs │ │ ├── lt-column-resizer.js │ │ ├── lt-foot.hbs │ │ ├── lt-foot.js │ │ ├── lt-head.hbs │ │ ├── lt-head.js │ │ ├── lt-infinity.hbs │ │ ├── lt-infinity.js │ │ ├── lt-row.hbs │ │ ├── lt-row.js │ │ ├── lt-scaffolding-row.hbs │ │ ├── lt-scaffolding-row.js │ │ ├── lt-scrollable.hbs │ │ ├── lt-scrollable.js │ │ ├── lt-spanned-row.hbs │ │ └── lt-spanned-row.js │ ├── helpers/ │ │ ├── compute.js │ │ └── html-safe.js │ ├── index.js │ ├── mixins/ │ │ ├── draggable-column.js │ │ └── table-header.js │ ├── styles/ │ │ └── addon.css │ └── utils/ │ ├── closest.js │ └── css-styleify.js ├── app/ │ ├── .gitkeep │ ├── components/ │ │ ├── light-table/ │ │ │ ├── cells/ │ │ │ │ └── base.js │ │ │ └── columns/ │ │ │ └── base.js │ │ ├── light-table.js │ │ ├── lt-body.js │ │ ├── lt-column-resizer.js │ │ ├── lt-foot.js │ │ ├── lt-head.js │ │ ├── lt-infinity.js │ │ ├── lt-row.js │ │ ├── lt-scaffolding-row.js │ │ ├── lt-scrollable.js │ │ └── lt-spanned-row.js │ └── helpers/ │ ├── compute.js │ └── html-safe.js ├── blueprints/ │ ├── cell-type/ │ │ ├── files/ │ │ │ └── app/ │ │ │ └── components/ │ │ │ └── light-table/ │ │ │ └── cells/ │ │ │ └── __name__.js │ │ └── index.js │ ├── column-type/ │ │ ├── files/ │ │ │ └── app/ │ │ │ └── components/ │ │ │ └── light-table/ │ │ │ └── columns/ │ │ │ └── __name__.js │ │ └── index.js │ └── ember-light-table/ │ └── index.js ├── ember-cli-build.js ├── index.js ├── package.json ├── testem.js ├── tests/ │ ├── dummy/ │ │ ├── app/ │ │ │ ├── adapters/ │ │ │ │ └── application.js │ │ │ ├── app.js │ │ │ ├── breakpoints.js │ │ │ ├── components/ │ │ │ │ ├── .gitkeep │ │ │ │ ├── base-table.js │ │ │ │ ├── code-panel.hbs │ │ │ │ ├── code-panel.js │ │ │ │ ├── code-snippet.hbs │ │ │ │ ├── colored-row.js │ │ │ │ ├── columns/ │ │ │ │ │ ├── draggable-table.hbs │ │ │ │ │ ├── draggable-table.js │ │ │ │ │ ├── grouped-table.hbs │ │ │ │ │ ├── grouped-table.js │ │ │ │ │ ├── resizable-table.hbs │ │ │ │ │ └── resizable-table.js │ │ │ │ ├── cookbook/ │ │ │ │ │ ├── client-side-table.hbs │ │ │ │ │ ├── client-side-table.js │ │ │ │ │ ├── custom-row-table.hbs │ │ │ │ │ ├── custom-row-table.js │ │ │ │ │ ├── custom-sort-icon-table.hbs │ │ │ │ │ ├── custom-sort-icon-table.js │ │ │ │ │ ├── horizontal-scrolling-table.hbs │ │ │ │ │ ├── horizontal-scrolling-table.js │ │ │ │ │ ├── index-list.hbs │ │ │ │ │ ├── occluded-table.hbs │ │ │ │ │ ├── occluded-table.js │ │ │ │ │ ├── paginated-table.hbs │ │ │ │ │ ├── paginated-table.js │ │ │ │ │ ├── table-actions-table.hbs │ │ │ │ │ └── table-actions-table.js │ │ │ │ ├── expanded-row.hbs │ │ │ │ ├── fa-icon-wrapper.hbs │ │ │ │ ├── materialize-icon.hbs │ │ │ │ ├── no-data.hbs │ │ │ │ ├── responsive-expanded-row.hbs │ │ │ │ ├── responsive-table.hbs │ │ │ │ ├── responsive-table.js │ │ │ │ ├── row-toggle.hbs │ │ │ │ ├── rows/ │ │ │ │ │ ├── expandable-table.hbs │ │ │ │ │ ├── expandable-table.js │ │ │ │ │ ├── selectable-table.hbs │ │ │ │ │ └── selectable-table.js │ │ │ │ ├── scrolling-table.hbs │ │ │ │ ├── scrolling-table.js │ │ │ │ ├── simple-table.hbs │ │ │ │ ├── simple-table.js │ │ │ │ ├── table-loader.hbs │ │ │ │ ├── user-actions.hbs │ │ │ │ └── user-avatar.hbs │ │ │ ├── controllers/ │ │ │ │ ├── .gitkeep │ │ │ │ └── application.js │ │ │ ├── helpers/ │ │ │ │ ├── .gitkeep │ │ │ │ └── classify.js │ │ │ ├── index.html │ │ │ ├── models/ │ │ │ │ ├── .gitkeep │ │ │ │ └── user.js │ │ │ ├── router.js │ │ │ ├── routes/ │ │ │ │ ├── .gitkeep │ │ │ │ ├── columns/ │ │ │ │ │ ├── draggable.js │ │ │ │ │ ├── grouped.js │ │ │ │ │ └── resizable.js │ │ │ │ ├── cookbook/ │ │ │ │ │ ├── custom-row.js │ │ │ │ │ ├── custom-sort-icon.js │ │ │ │ │ ├── horizontal-scrolling.js │ │ │ │ │ ├── index.js │ │ │ │ │ ├── occlusion-rendering.js │ │ │ │ │ ├── pagination.js │ │ │ │ │ ├── sorting.js │ │ │ │ │ └── table-actions.js │ │ │ │ ├── cookbook.js │ │ │ │ ├── index.js │ │ │ │ ├── responsive.js │ │ │ │ ├── rows/ │ │ │ │ │ ├── expandable.js │ │ │ │ │ └── selectable.js │ │ │ │ ├── scrolling.js │ │ │ │ └── table-route.js │ │ │ ├── serializers/ │ │ │ │ └── application.js │ │ │ ├── styles/ │ │ │ │ ├── app.scss │ │ │ │ ├── loader.scss │ │ │ │ └── table.scss │ │ │ └── templates/ │ │ │ ├── application.hbs │ │ │ ├── columns/ │ │ │ │ ├── draggable.hbs │ │ │ │ ├── grouped.hbs │ │ │ │ └── resizable.hbs │ │ │ ├── cookbook/ │ │ │ │ ├── client-side.hbs │ │ │ │ ├── custom-row.hbs │ │ │ │ ├── custom-sort-icon.hbs │ │ │ │ ├── horizontal-scrolling.hbs │ │ │ │ ├── index.hbs │ │ │ │ ├── occlusion-rendering.hbs │ │ │ │ ├── pagination.hbs │ │ │ │ └── table-actions.hbs │ │ │ ├── index.hbs │ │ │ ├── responsive.hbs │ │ │ ├── rows/ │ │ │ │ ├── expandable.hbs │ │ │ │ └── selectable.hbs │ │ │ └── scrolling.hbs │ │ ├── config/ │ │ │ ├── ember-cli-update.json │ │ │ ├── ember-try.js │ │ │ ├── environment.js │ │ │ ├── icons.js │ │ │ ├── optional-features.json │ │ │ └── targets.js │ │ ├── mirage/ │ │ │ ├── config.js │ │ │ ├── factories/ │ │ │ │ └── user.js │ │ │ ├── models/ │ │ │ │ └── user.js │ │ │ ├── scenarios/ │ │ │ │ └── default.js │ │ │ └── serializers/ │ │ │ └── application.js │ │ └── public/ │ │ └── robots.txt │ ├── helpers/ │ │ ├── has-class.js │ │ ├── index.js │ │ ├── responsive.js │ │ └── table-columns.js │ ├── index.html │ ├── integration/ │ │ ├── .gitkeep │ │ ├── components/ │ │ │ ├── light-table/ │ │ │ │ ├── cells/ │ │ │ │ │ └── base-test.js │ │ │ │ └── columns/ │ │ │ │ └── base-test.js │ │ │ ├── light-table-occlusion-test.js │ │ │ ├── light-table-test.js │ │ │ ├── lt-body-occlusion-test.js │ │ │ ├── lt-body-test.js │ │ │ ├── lt-column-resizer-test.js │ │ │ ├── lt-foot-test.js │ │ │ ├── lt-head-test.js │ │ │ ├── lt-infinity-test.js │ │ │ ├── lt-row-test.js │ │ │ ├── lt-scaffolding-row-test.js │ │ │ ├── lt-scrollable-test.js │ │ │ └── lt-spanned-row-test.js │ │ └── helpers/ │ │ ├── compute-test.js │ │ └── html-safe-test.js │ ├── test-helper.js │ └── unit/ │ ├── .gitkeep │ ├── classes/ │ │ ├── column-test.js │ │ ├── row-test.js │ │ └── table-test.js │ └── mixins/ │ └── table-header-test.js └── yuidoc.json
SYMBOL INDEX (180 symbols across 49 files)
FILE: addon/-private/global-options.js
function mergeOptionsWithGlobals (line 7) | function mergeOptionsWithGlobals(options) {
FILE: addon/classes/Column.js
class Column (line 13) | class Column extends EmberObject.extend({
method init (line 328) | init(options = {}) {
FILE: addon/classes/Row.js
class Row (line 12) | class Row extends ObjectProxy.extend({
FILE: addon/classes/Table.js
class Table (line 21) | class Table extends EmberObject.extend({
method init (line 149) | init(options = {}) {
method setRows (line 178) | setRows(rows = [], options = {}) {
method addRow (line 188) | addRow(row, options = {}) {
method addRows (line 202) | addRows(rows = [], options = {}) {
method pushRow (line 213) | pushRow(row, options = {}) {
method pushRows (line 226) | pushRows(rows = [], options = {}) {
method insertRowAt (line 240) | insertRowAt(index, row, options = {}) {
method removeRow (line 251) | removeRow(row) {
method removeRows (line 264) | removeRows(rows = []) {
method removeRowAt (line 273) | removeRowAt(index) {
method setColumns (line 285) | setColumns(columns = []) {
method addColumn (line 294) | addColumn(column) {
method addColumns (line 303) | addColumns(columns = []) {
method pushColumn (line 313) | pushColumn(column) {
method pushColumns (line 325) | pushColumns(columns = []) {
method insertColumnAt (line 338) | insertColumnAt(index, column) {
method removeColumn (line 349) | removeColumn(column) {
method removeColumns (line 358) | removeColumns(columns = []) {
method removeColumnAt (line 367) | removeColumnAt(index) {
method createRow (line 379) | static createRow(content, options = {}) {
method createRows (line 395) | static createRows(rows = [], options = {}) {
method createColumn (line 406) | static createColumn(column) {
method createColumns (line 421) | static createColumns(columns = []) {
FILE: addon/components/columns/base.js
method get (line 118) | get() {
method set (line 127) | set(key, value) {
FILE: addon/components/light-table.js
function intersections (line 12) | function intersections(array1, array2) {
method init (line 287) | init() {
method _displayColumns (line 342) | _displayColumns(numColumns) {
method onBeforeResponsiveChange (line 361) | onBeforeResponsiveChange() {}
method onAfterResponsiveChange (line 362) | onAfterResponsiveChange() {}
method onBeforeResponsiveChange (line 372) | onBeforeResponsiveChange(/* matches */) {
method onAfterResponsiveChange (line 383) | onAfterResponsiveChange(/* matches */) {
FILE: addon/components/lt-body.js
method init (line 340) | init() {
method destroy (line 351) | destroy() {
method _setupVirtualScrollbar (line 356) | _setupVirtualScrollbar() {
method checkTargetScrollOffset (line 404) | checkTargetScrollOffset() {
method toggleExpandedRow (line 420) | toggleExpandedRow(row) {
method _debounceScrolledToBottom (line 435) | _debounceScrolledToBottom(delay = 100) {
method _cancelTimers (line 446) | _cancelTimers() {
method onRowClick (line 454) | onRowClick() {}
method onRowDoubleClick (line 455) | onRowDoubleClick() {}
method onScroll (line 456) | onScroll() {}
method firstVisibleChanged (line 457) | firstVisibleChanged() {}
method lastVisibleChanged (line 458) | lastVisibleChanged() {}
method firstReached (line 459) | firstReached() {}
method lastReached (line 460) | lastReached() {}
method onRowClick (line 485) | onRowClick(row, e) {
method onRowDoubleClick (line 540) | onRowDoubleClick(/* row */) {
method onScroll (line 554) | onScroll(scrollOffset /* , event */) {
method firstVisibleChanged (line 559) | firstVisibleChanged(item, index /* , key */) {
method lastVisibleChanged (line 566) | lastVisibleChanged(/* item, index, key */) {
method firstReached (line 570) | firstReached(/* item, index, key */) {
method lastReached (line 574) | lastReached(/* item, index, key */) {
FILE: addon/components/lt-column-resizer.js
constant TOP_LEVEL_CLASS (line 4) | const TOP_LEVEL_CLASS = '.ember-light-table';
method colElement (line 15) | colElement() {
method didInsertElement (line 19) | didInsertElement() {
method willDestroyElement (line 29) | willDestroyElement() {
method click (line 35) | click(e) {
method mouseDown (line 43) | mouseDown(e) {
method _mouseUp (line 59) | _mouseUp(e) {
method _mouseMove (line 76) | _mouseMove(e) {
method onColumnResized (line 118) | onColumnResized() {}
FILE: addon/components/lt-head.js
class LtHeadComponent (line 36) | class LtHeadComponent extends Component.extend(
FILE: addon/components/lt-infinity.js
method didInsertElement (line 11) | didInsertElement() {
method willDestroyElement (line 33) | willDestroyElement() {
method didEnterViewport (line 38) | didEnterViewport() {
method didExitViewport (line 42) | didExitViewport() {
FILE: addon/helpers/compute.js
function compute (line 5) | function compute([action, ...params]) {
FILE: addon/mixins/draggable-column.js
method isDropTarget (line 46) | isDropTarget() {
method dragStart (line 58) | dragStart(e) {
method dragEnter (line 81) | dragEnter(e) {
method dragOver (line 90) | dragOver(e) {
method dragLeave (line 106) | dragLeave() {
method dragEnd (line 111) | dragEnd() {
method drop (line 131) | drop(e) {
method destroy (line 157) | destroy() {
method onColumnDrag (line 163) | onColumnDrag() {}
method onColumnDrop (line 164) | onColumnDrop() {}
FILE: addon/mixins/table-header.js
method init (line 164) | init() {
method onColumnClick (line 188) | onColumnClick(column) {
method onColumnDoubleClick (line 211) | onColumnDoubleClick(/* column */) {
method onColumnResized (line 222) | onColumnResized(/* column, width */) {
method onColumnDrag (line 232) | onColumnDrag(/* column */) {
method onColumnDrop (line 243) | onColumnDrop(/* column, isSuccess */) {
FILE: addon/utils/css-styleify.js
function cssStyleify (line 5) | function cssStyleify(hash = {}) {
FILE: blueprints/ember-light-table/index.js
method normalizeEntityName (line 5) | normalizeEntityName() {}
method beforeInstall (line 7) | beforeInstall() {
FILE: tests/dummy/app/adapters/application.js
class Application (line 4) | class Application extends JSONAPIAdapter {
FILE: tests/dummy/app/app.js
class App (line 6) | class App extends Application {
FILE: tests/dummy/app/components/base-table.js
class BaseTable (line 10) | class BaseTable extends Component {
method constructor (line 22) | constructor() {
method isLoading (line 41) | get isLoading() {
method fetchRecords (line 45) | @restartableTask *fetchRecords() {
method onScrolledToBottom (line 59) | @action
method onColumnClick (line 67) | @action
FILE: tests/dummy/app/components/code-panel.js
class CodePanel (line 5) | class CodePanel extends Component {
FILE: tests/dummy/app/components/colored-row.js
class ColoredRow (line 10) | class ColoredRow extends Row {
method style (line 11) | get style() {
FILE: tests/dummy/app/components/columns/draggable-table.js
class DraggableTable (line 4) | class DraggableTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/components/columns/grouped-table.js
class GroupedTable (line 4) | class GroupedTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/components/columns/resizable-table.js
class ResizableTable (line 4) | class ResizableTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/components/cookbook/client-side-table.js
class PaginatedTable (line 8) | class PaginatedTable extends BaseTable {
method sortedModel (line 18) | get sortedModel() {
method isLoading (line 23) | get isLoading() {
method possibleFilters (line 27) | get possibleFilters() {
method columns (line 31) | get columns() {
method constructor (line 65) | constructor() {
method fetchRecords (line 71) | @restartableTask *fetchRecords() {
method setRows (line 80) | @restartableTask *setRows(rows) {
method filterAndSortModel (line 86) | @restartableTask *filterAndSortModel(debounceMs = 200) {
method onColumnClick (line 104) | @action
method updateQuery (line 113) | @action
method onSearchChange (line 118) | @action
FILE: tests/dummy/app/components/cookbook/custom-row-table.js
class CustomRowTable (line 4) | class CustomRowTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/components/cookbook/custom-sort-icon-table.js
class CustomSortIconTable (line 4) | class CustomSortIconTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/components/cookbook/horizontal-scrolling-table.js
class HorizontalScrollingTable (line 4) | class HorizontalScrollingTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/components/cookbook/occluded-table.js
class OccludedTable (line 4) | class OccludedTable extends BaseTable {
method columns (line 7) | get columns() {
method constructor (line 41) | constructor() {
FILE: tests/dummy/app/components/cookbook/paginated-table.js
class PaginatedTable (line 5) | class PaginatedTable extends BaseTable {
method columns (line 8) | get columns() {
method constructor (line 42) | constructor() {
method setPage (line 48) | @action
FILE: tests/dummy/app/components/cookbook/table-actions-table.js
class TableActionsTable (line 5) | class TableActionsTable extends BaseTable {
method columns (line 6) | get columns() {
method deleteUser (line 46) | @action
method notifyUser (line 60) | @action
FILE: tests/dummy/app/components/responsive-table.js
class ResponsiveTable (line 5) | class ResponsiveTable extends BaseTable {
method columns (line 6) | get columns() {
method onAfterResponsiveChange (line 50) | @action
FILE: tests/dummy/app/components/rows/expandable-table.js
class ExpandableTable (line 4) | class ExpandableTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/components/rows/selectable-table.js
class ExpandableTable (line 5) | class ExpandableTable extends BaseTable {
method hasSelection (line 6) | get hasSelection() {
method columns (line 10) | get columns() {
method selectAll (line 44) | @action
method deselectAll (line 49) | @action
method deleteAll (line 54) | @action
FILE: tests/dummy/app/components/scrolling-table.js
class ScrollingTable (line 5) | class ScrollingTable extends BaseTable {
method columns (line 10) | get columns() {
method updateScrollPos (line 44) | @action
FILE: tests/dummy/app/components/simple-table.js
class SimpleTable (line 4) | class SimpleTable extends BaseTable {
method columns (line 5) | get columns() {
FILE: tests/dummy/app/controllers/application.js
class ApplicationController (line 4) | class ApplicationController extends Controller {
FILE: tests/dummy/app/models/user.js
class User (line 3) | class User extends Model {
FILE: tests/dummy/app/router.js
class Router (line 4) | class Router extends EmberRouter {
FILE: tests/dummy/app/routes/table-route.js
class TableRouteRoute (line 4) | class TableRouteRoute extends Route {
method model (line 5) | model() {
method resetController (line 9) | resetController(controller, isExiting) {
FILE: tests/dummy/mirage/config.js
function routes (line 16) | function routes() {
FILE: tests/dummy/mirage/factories/user.js
constant MATERIAL_UI_COLORS (line 11) | const MATERIAL_UI_COLORS = [
FILE: tests/helpers/has-class.js
function hasClass (line 1) | function hasClass(elem, cls) {
FILE: tests/helpers/index.js
function setupApplicationTest (line 11) | function setupApplicationTest(hooks, options) {
function setupRenderingTest (line 30) | function setupRenderingTest(hooks, options) {
function setupTest (line 36) | function setupTest(hooks, options) {
FILE: tests/helpers/responsive.js
method _forceSetBreakpoint (line 18) | _forceSetBreakpoint(breakpoint) {
method match (line 40) | match() {}
method init (line 42) | init() {
function setBreakpointForIntegrationTest (line 55) | function setBreakpointForIntegrationTest(container, breakpoint) {
FILE: tests/integration/components/light-table-occlusion-test.js
method didReceiveAttrs (line 281) | didReceiveAttrs() {
method click (line 290) | click() {
FILE: tests/integration/components/light-table-test.js
method onScroll (line 315) | onScroll(actualScroll) {
method didReceiveAttrs (line 348) | didReceiveAttrs() {
method click (line 357) | click() {
FILE: tests/integration/components/light-table/cells/base-test.js
method format (line 23) | format(value) {
method format (line 42) | format() {
method format (line 62) | format(value) {
FILE: tests/integration/components/lt-head-test.js
method init (line 157) | init() {
FILE: tests/unit/classes/table-test.js
method objectAtContent (line 56) | objectAtContent(index) {
Condensed preview — 216 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (323K chars).
[
{
"path": ".editorconfig",
"chars": 367,
"preview": "# EditorConfig helps developers define and maintain consistent\n# coding styles between different editors and IDEs\n# edit"
},
{
"path": ".ember-cli",
"chars": 525,
"preview": "{\n /**\n Ember CLI sends analytics information by default. The data is completely\n anonymous, but there are times "
},
{
"path": ".eslintignore",
"chars": 338,
"preview": "# unconventional js\n/blueprints/*/files/\n/vendor/\n\n# compiled output\n/dist/\n/tmp/\n\n# dependencies\n/bower_components/\n/no"
},
{
"path": ".eslintrc.js",
"chars": 1708,
"preview": "'use strict';\n\nmodule.exports = {\n root: true,\n parser: 'babel-eslint',\n parserOptions: {\n ecmaVersion: 2018,\n "
},
{
"path": ".github/workflows/ci.yml",
"chars": 1806,
"preview": "name: CI\n\non:\n push:\n branches:\n - main\n - master\n pull_request: {}\n\nconcurrency:\n group: ci-${{ github."
},
{
"path": ".gitignore",
"chars": 575,
"preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# compiled output\n/dist/\n/tmp/\n\n# dependenci"
},
{
"path": ".npmignore",
"chars": 544,
"preview": "# compiled output\n/dist/\n/tmp/\n\n# dependencies\n/bower_components/\n\n# misc\n/.bowerrc\n/.editorconfig\n/.ember-cli\n/.env*\n/."
},
{
"path": ".prettierignore",
"chars": 346,
"preview": "# unconventional js\n/blueprints/*/files/\n/vendor/\n\n# compiled output\n/dist/\n/tmp/\n\n# dependencies\n/bower_components/\n/no"
},
{
"path": ".prettierrc.js",
"chars": 197,
"preview": "'use strict';\n\nmodule.exports = {\n singleQuote: true,\n overrides: [\n {\n files: '**/*.hbs',\n options: {\n "
},
{
"path": ".template-lintrc.js",
"chars": 516,
"preview": "'use strict';\n\nmodule.exports = {\n extends: 'recommended',\n rules: {\n 'no-action': false,\n 'no-curly-component-i"
},
{
"path": ".tool-versions",
"chars": 14,
"preview": "nodejs 14.20.0"
},
{
"path": ".watchmanconfig",
"chars": 37,
"preview": "{\n \"ignore_dirs\": [\"tmp\", \"dist\"]\n}\n"
},
{
"path": "CHANGELOG.md",
"chars": 38283,
"preview": "Changelog\n=========\n\n\n\n## v3.0.0-beta.2 (2023-01-17)\n\n#### :boom: Breaking Change\n* [#809](https://github.com/adopted-em"
},
{
"path": "CONTRIBUTING.md",
"chars": 626,
"preview": "# How To Contribute\n\n## Installation\n\n* `git clone <repository-url>`\n* `cd ember-light-table`\n* `yarn install`\n\n## Linti"
},
{
"path": "LICENSE.md",
"chars": 1073,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2016 - 2019\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "README.md",
"chars": 6322,
"preview": "<div align=\"center\">\n <a href=\"https://adopted-ember-addons.github.io/ember-light-table/\">\n <img\n src=\"https://"
},
{
"path": "RELEASE.md",
"chars": 2187,
"preview": "# Release Process\n\nReleases are mostly automated using\n[release-it](https://github.com/release-it/release-it/) and\n[lern"
},
{
"path": "addon/-private/global-options.js",
"chars": 234,
"preview": "import config from 'ember-get-config';\n\nconst globalOptions = config['ember-light-table'] || {};\n\nexport default globalO"
},
{
"path": "addon/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "addon/classes/Column.js",
"chars": 7231,
"preview": "import { A as emberArray, makeArray } from '@ember/array';\nimport EmberObject, { computed } from '@ember/object';\nimport"
},
{
"path": "addon/classes/Row.js",
"chars": 1675,
"preview": "import ObjectProxy from '@ember/object/proxy';\nimport { computed } from '@ember/object';\nimport { guidFor } from '@ember"
},
{
"path": "addon/classes/Table.js",
"chars": 10163,
"preview": "import { A as emberArray, isArray } from '@ember/array';\nimport { assert } from '@ember/debug';\nimport EmberObject, { co"
},
{
"path": "addon/components/cells/base.hbs",
"chars": 305,
"preview": "{{#if this.column.cellComponent}}\n {{component\n (ensure-safe-component this.column.cellComponent)\n tableActions=t"
},
{
"path": "addon/components/cells/base.js",
"chars": 1823,
"preview": "import Component from '@ember/component';\nimport { computed } from '@ember/object';\nimport { readOnly } from '@ember/obj"
},
{
"path": "addon/components/columns/base.hbs",
"chars": 867,
"preview": "{{#if this.column.component}}\n {{component\n (ensure-safe-component this.column.component)\n column=this.column\n "
},
{
"path": "addon/components/columns/base.js",
"chars": 2858,
"preview": "import { set } from '@ember/object';\nimport Component from '@ember/component';\nimport { computed } from '@ember/object';"
},
{
"path": "addon/components/light-table.hbs",
"chars": 957,
"preview": "<div\n class=\"ember-light-table {{if this.occlusion \"occlusion\"}}\"\n id={{or @id this.tableId}}\n style={{this.style}}\n "
},
{
"path": "addon/components/light-table.js",
"chars": 9370,
"preview": "import { A as emberArray } from '@ember/array';\nimport Component from '@ember/component';\nimport { computed, observer } "
},
{
"path": "addon/components/lt-body.hbs",
"chars": 6764,
"preview": "<div\n class=\"lt-body-wrap\n {{if this.canSelect \"can-select\"}}\n {{if this.multiSelect \"multi-select\"}}\n {{if this.c"
},
{
"path": "addon/components/lt-body.js",
"chars": 14395,
"preview": "import Component from '@ember/component';\nimport { action, computed } from '@ember/object';\nimport { readOnly } from '@e"
},
{
"path": "addon/components/lt-column-resizer.hbs",
"chars": 10,
"preview": "{{yield}}\n"
},
{
"path": "addon/components/lt-column-resizer.js",
"chars": 2994,
"preview": "import Component from '@ember/component';\nimport closest from 'ember-light-table/utils/closest';\n\nconst TOP_LEVEL_CLASS "
},
{
"path": "addon/components/lt-foot.hbs",
"chars": 1111,
"preview": "<EmberWormhole\n @to={{concat this.tableId \"_inline_foot\"}}\n @renderInPlace={{this.renderInPlace}}\n>\n <table class={{t"
},
{
"path": "addon/components/lt-foot.js",
"chars": 854,
"preview": "import Component from '@ember/component';\nimport TableHeaderMixin from 'ember-light-table/mixins/table-header';\n\n/**\n * "
},
{
"path": "addon/components/lt-head.hbs",
"chars": 2314,
"preview": "<div class=\"lt-head-wrap\">\n <EmberWormhole\n @to={{concat this.tableId \"_inline_head\"}}\n @renderInPlace={{this.ren"
},
{
"path": "addon/components/lt-head.js",
"chars": 1036,
"preview": "import Component from '@ember/component';\nimport TableHeaderMixin from 'ember-light-table/mixins/table-header';\nimport c"
},
{
"path": "addon/components/lt-infinity.hbs",
"chars": 10,
"preview": "{{yield}}\n"
},
{
"path": "addon/components/lt-infinity.js",
"chars": 886,
"preview": "import Component from '@ember/component';\nimport { inject as service } from '@ember/service';\n\nexport default Component."
},
{
"path": "addon/components/lt-row.hbs",
"chars": 270,
"preview": "{{#each this.columns as |column|}}\n {{component\n (concat 'light-table/cells/' column.cellType)\n column=column\n "
},
{
"path": "addon/components/lt-row.js",
"chars": 575,
"preview": "import Component from '@ember/component';\nimport { readOnly } from '@ember/object/computed';\n\nexport default Component.e"
},
{
"path": "addon/components/lt-scaffolding-row.hbs",
"chars": 244,
"preview": "{{#each this.columns as |column|}}\n {{! template-lint-disable no-inline-styles }}\n <td style={{html-safe (if column.wi"
},
{
"path": "addon/components/lt-scaffolding-row.js",
"chars": 136,
"preview": "import Component from '@ember/component';\n\nexport default Component.extend({\n classNames: ['lt-scaffolding-row'],\n tag"
},
{
"path": "addon/components/lt-scrollable.hbs",
"chars": 334,
"preview": "{{#if this.virtualScrollbar}}\n <EmberScrollable\n class=\"lt-scrollable\"\n @autoHide={{this.autoHide}}\n @horizont"
},
{
"path": "addon/components/lt-scrollable.js",
"chars": 135,
"preview": "import Component from '@ember/component';\n\nexport default Component.extend({\n tagName: '',\n vertical: true,\n horizont"
},
{
"path": "addon/components/lt-spanned-row.hbs",
"chars": 157,
"preview": "{{#if this.visible}}\n <tr class=\"lt-row {{html-safe this.classes}}\">\n <td colspan={{this.colspan}}>\n {{yield th"
},
{
"path": "addon/components/lt-spanned-row.js",
"chars": 127,
"preview": "import Component from '@ember/component';\n\nexport default Component.extend({\n colspan: 1,\n tagName: '',\n visible: tru"
},
{
"path": "addon/helpers/compute.js",
"chars": 255,
"preview": "// https://github.com/DockYard/ember-composable-helpers/blob/master/addon/helpers/compute.js\n\nimport { helper } from '@e"
},
{
"path": "addon/helpers/html-safe.js",
"chars": 201,
"preview": "import { helper } from '@ember/component/helper';\nimport { htmlSafe as _htmlSafe } from '@ember/template';\n\nexport defau"
},
{
"path": "addon/index.js",
"chars": 2725,
"preview": "import Table from './classes/Table';\nimport Column from './classes/Column';\nimport Row from './classes/Row';\n\n/**\n * ## "
},
{
"path": "addon/mixins/draggable-column.js",
"chars": 4127,
"preview": "import Mixin from '@ember/object/mixin';\nimport { computed } from '@ember/object';\nimport { cancel, next } from '@ember/"
},
{
"path": "addon/mixins/table-header.js",
"chars": 6119,
"preview": "import Mixin from '@ember/object/mixin';\nimport { computed, trySet } from '@ember/object';\nimport { oneWay, readOnly } f"
},
{
"path": "addon/styles/addon.css",
"chars": 2453,
"preview": ".ember-light-table {\n height: inherit;\n overflow: auto;\n display: -webkit-box;\n display: -ms-flexbox;\n display: fle"
},
{
"path": "addon/utils/closest.js",
"chars": 450,
"preview": "/**\n * A polyfill for jQuery .closest() method\n * @param { Object } el Dom element to start from\n * @param { Strin"
},
{
"path": "addon/utils/css-styleify.js",
"chars": 397,
"preview": "import { dasherize } from '@ember/string';\nimport { htmlSafe } from '@ember/template';\nimport { isPresent } from '@ember"
},
{
"path": "app/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "app/components/light-table/cells/base.js",
"chars": 67,
"preview": "export { default } from 'ember-light-table/components/cells/base';\n"
},
{
"path": "app/components/light-table/columns/base.js",
"chars": 69,
"preview": "export { default } from 'ember-light-table/components/columns/base';\n"
},
{
"path": "app/components/light-table.js",
"chars": 68,
"preview": "export { default } from 'ember-light-table/components/light-table';\n"
},
{
"path": "app/components/lt-body.js",
"chars": 64,
"preview": "export { default } from 'ember-light-table/components/lt-body';\n"
},
{
"path": "app/components/lt-column-resizer.js",
"chars": 74,
"preview": "export { default } from 'ember-light-table/components/lt-column-resizer';\n"
},
{
"path": "app/components/lt-foot.js",
"chars": 64,
"preview": "export { default } from 'ember-light-table/components/lt-foot';\n"
},
{
"path": "app/components/lt-head.js",
"chars": 64,
"preview": "export { default } from 'ember-light-table/components/lt-head';\n"
},
{
"path": "app/components/lt-infinity.js",
"chars": 68,
"preview": "export { default } from 'ember-light-table/components/lt-infinity';\n"
},
{
"path": "app/components/lt-row.js",
"chars": 63,
"preview": "export { default } from 'ember-light-table/components/lt-row';\n"
},
{
"path": "app/components/lt-scaffolding-row.js",
"chars": 75,
"preview": "export { default } from 'ember-light-table/components/lt-scaffolding-row';\n"
},
{
"path": "app/components/lt-scrollable.js",
"chars": 70,
"preview": "export { default } from 'ember-light-table/components/lt-scrollable';\n"
},
{
"path": "app/components/lt-spanned-row.js",
"chars": 71,
"preview": "export { default } from 'ember-light-table/components/lt-spanned-row';\n"
},
{
"path": "app/helpers/compute.js",
"chars": 70,
"preview": "export { default, compute } from 'ember-light-table/helpers/compute';\n"
},
{
"path": "app/helpers/html-safe.js",
"chars": 73,
"preview": "export { default, htmlSafe } from 'ember-light-table/helpers/html-safe';\n"
},
{
"path": "blueprints/cell-type/files/app/components/light-table/cells/__name__.js",
"chars": 95,
"preview": "import Cell from 'ember-light-table/components/cells/base';\n\nexport default Cell.extend({\n\n});\n"
},
{
"path": "blueprints/cell-type/index.js",
"chars": 105,
"preview": "/* jshint node:true*/\nmodule.exports = {\n description: 'Generates a cell type and integration test',\n};\n"
},
{
"path": "blueprints/column-type/files/app/components/light-table/columns/__name__.js",
"chars": 101,
"preview": "import Column from 'ember-light-table/components/columns/base';\n\nexport default Column.extend({\n\n});\n"
},
{
"path": "blueprints/column-type/index.js",
"chars": 107,
"preview": "/* jshint node:true*/\nmodule.exports = {\n description: 'Generates a column type and integration test',\n};\n"
},
{
"path": "blueprints/ember-light-table/index.js",
"chars": 211,
"preview": "/* jshint node:true*/\nmodule.exports = {\n description: 'Install Ember Light Table dependencies',\n\n normalizeEntityName"
},
{
"path": "ember-cli-build.js",
"chars": 701,
"preview": "'use strict';\n\nconst EmberAddon = require('ember-cli/lib/broccoli/ember-addon');\n\nmodule.exports = function (defaults) {"
},
{
"path": "index.js",
"chars": 72,
"preview": "'use strict';\n\nmodule.exports = {\n name: require('./package').name,\n};\n"
},
{
"path": "package.json",
"chars": 4275,
"preview": "{\n \"name\": \"ember-light-table\",\n \"version\": \"3.0.0-beta.2\",\n \"description\": \"Lightweight, component based table\",\n \""
},
{
"path": "testem.js",
"chars": 589,
"preview": "'use strict';\n\nmodule.exports = {\n test_page: 'tests/index.html?hidepassed',\n disable_watching: true,\n launch_in_ci: "
},
{
"path": "tests/dummy/app/adapters/application.js",
"chars": 196,
"preview": "import JSONAPIAdapter from '@ember-data/adapter/json-api';\nimport ENV from '../config/environment';\n\nexport default clas"
},
{
"path": "tests/dummy/app/app.js",
"chars": 388,
"preview": "import Application from '@ember/application';\nimport Resolver from 'ember-resolver';\nimport loadInitializers from 'ember"
},
{
"path": "tests/dummy/app/breakpoints.js",
"chars": 229,
"preview": "/* eslint-disable key-spacing */\nexport default {\n mobile: '(max-width: 768px)',\n tablet: '(min-width: 769px) and (max"
},
{
"path": "tests/dummy/app/components/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "tests/dummy/app/components/base-table.js",
"chars": 1873,
"preview": "// BEGIN-SNIPPET base-table\nimport Component from '@glimmer/component';\nimport { action } from '@ember/object';\nimport {"
},
{
"path": "tests/dummy/app/components/code-panel.hbs",
"chars": 1637,
"preview": "<div\n class=\"panel-group\"\n id={{concat this.elementId \"-code-panel\"}}\n role=\"tablist\"\n>\n <div class=\"panel panel-def"
},
{
"path": "tests/dummy/app/components/code-panel.js",
"chars": 251,
"preview": "import Component from '@glimmer/component';\nimport { tracked } from '@glimmer/tracking';\nimport { guidFor } from '@ember"
},
{
"path": "tests/dummy/app/components/code-snippet.hbs",
"chars": 285,
"preview": "{{! https://github.com/ef4/ember-code-snippet/blob/master/CHANGELOG.md#300}}\n{{#let (get-code-snippet @name) as |snippet"
},
{
"path": "tests/dummy/app/components/colored-row.js",
"chars": 468,
"preview": "// BEGIN-SNIPPET colored-row\nimport classic from 'ember-classic-decorator';\nimport { classNames, attributeBindings } fro"
},
{
"path": "tests/dummy/app/components/columns/draggable-table.hbs",
"chars": 754,
"preview": "{{! BEGIN-SNIPPET draggable-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n <t.head\n @onColumnCli"
},
{
"path": "tests/dummy/app/components/columns/draggable-table.js",
"chars": 1390,
"preview": "// BEGIN-SNIPPET draggable-table\nimport BaseTable from '../base-table';\n\nexport default class DraggableTable extends Bas"
},
{
"path": "tests/dummy/app/components/columns/grouped-table.hbs",
"chars": 542,
"preview": "{{! BEGIN-SNIPPET grouped-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n <t.head\n @onColumnClick"
},
{
"path": "tests/dummy/app/components/columns/grouped-table.js",
"chars": 1135,
"preview": "// BEGIN-SNIPPET grouped-table\nimport BaseTable from '../base-table';\n\nexport default class GroupedTable extends BaseTab"
},
{
"path": "tests/dummy/app/components/columns/resizable-table.hbs",
"chars": 774,
"preview": "{{! BEGIN-SNIPPET resizable-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n <t.head\n @onColumnCli"
},
{
"path": "tests/dummy/app/components/columns/resizable-table.js",
"chars": 1447,
"preview": "// BEGIN-SNIPPET resizable-table\nimport BaseTable from '../base-table';\n\nexport default class ResizableTable extends Bas"
},
{
"path": "tests/dummy/app/components/cookbook/client-side-table.hbs",
"chars": 1536,
"preview": "{{! BEGIN-SNIPPET client-side-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n {{!\n In order for `"
},
{
"path": "tests/dummy/app/components/cookbook/client-side-table.js",
"chars": 2781,
"preview": "// BEGIN-SNIPPET client-side-table\nimport BaseTable from '../base-table';\nimport { action } from '@ember/object';\nimport"
},
{
"path": "tests/dummy/app/components/cookbook/custom-row-table.hbs",
"chars": 776,
"preview": "{{! BEGIN-SNIPPET custom-row-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n {{!\n In order for `s"
},
{
"path": "tests/dummy/app/components/cookbook/custom-row-table.js",
"chars": 763,
"preview": "// BEGIN-SNIPPET custom-row-table\nimport BaseTable from '../base-table';\n\nexport default class CustomRowTable extends Ba"
},
{
"path": "tests/dummy/app/components/cookbook/custom-sort-icon-table.hbs",
"chars": 588,
"preview": "{{!-- BEGIN-SNIPPET custom-sort-icon-table --}}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n\n <t.head\n "
},
{
"path": "tests/dummy/app/components/cookbook/custom-sort-icon-table.js",
"chars": 774,
"preview": "// BEGIN-SNIPPET custom-sort-icon-table\nimport BaseTable from '../base-table';\n\nexport default class CustomSortIconTable"
},
{
"path": "tests/dummy/app/components/cookbook/horizontal-scrolling-table.hbs",
"chars": 740,
"preview": "{{! BEGIN-SNIPPET horizontal-scrolling-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n {{!\n In or"
},
{
"path": "tests/dummy/app/components/cookbook/horizontal-scrolling-table.js",
"chars": 855,
"preview": "// BEGIN-SNIPPET horizontal-scrolling-table\nimport BaseTable from '../base-table';\n\nexport default class HorizontalScrol"
},
{
"path": "tests/dummy/app/components/cookbook/index-list.hbs",
"chars": 1329,
"preview": "<dl>\n <dt><LinkTo @route=\"cookbook.client-side\">Client Side Search & Sort</LinkTo></dt>\n <dd>\n <p>Fully searchable "
},
{
"path": "tests/dummy/app/components/cookbook/occluded-table.hbs",
"chars": 678,
"preview": "{{!-- BEGIN-SNIPPET occluded-table --}}\n<LightTable\n @table={{this.table}}\n @height=\"65vh\"\n @occlusion={{true}}\n @es"
},
{
"path": "tests/dummy/app/components/cookbook/occluded-table.js",
"chars": 876,
"preview": "// BEGIN-SNIPPET occluded-table\nimport BaseTable from '../base-table';\n\nexport default class OccludedTable extends BaseT"
},
{
"path": "tests/dummy/app/components/cookbook/paginated-table.hbs",
"chars": 1974,
"preview": "{{! BEGIN-SNIPPET paginated-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n {{!\n In order for `so"
},
{
"path": "tests/dummy/app/components/cookbook/paginated-table.js",
"chars": 1194,
"preview": "// BEGIN-SNIPPET paginated-table\nimport BaseTable from '../base-table';\nimport { action } from '@ember/object';\n\nexport "
},
{
"path": "tests/dummy/app/components/cookbook/table-actions-table.hbs",
"chars": 825,
"preview": "{{! BEGIN-SNIPPET table-actions-table }}\n<LightTable\n @table={{this.table}}\n @height=\"65vh\"\n @tableActions={{\n has"
},
{
"path": "tests/dummy/app/components/cookbook/table-actions-table.js",
"chars": 1360,
"preview": "// BEGIN-SNIPPET table-actions-table\nimport BaseTable from '../base-table';\nimport { action } from '@ember/object';\n\nexp"
},
{
"path": "tests/dummy/app/components/expanded-row.hbs",
"chars": 478,
"preview": "{{!-- BEGIN-SNIPPET expanded-row --}}\n<div class=\"row\">\n <div class=\"col-md-2\">\n <img src={{@row.avatar}} class=\"use"
},
{
"path": "tests/dummy/app/components/fa-icon-wrapper.hbs",
"chars": 52,
"preview": "<FaIcon @icon={{get @sortIcons @sortIconProperty}}/>"
},
{
"path": "tests/dummy/app/components/materialize-icon.hbs",
"chars": 162,
"preview": "{{!-- BEGIN-SNIPPET materialize-icon --}}\n<span>\n <i class=\"lt-sort-icon material-icons\">{{get @sortIcons @sortIconProp"
},
{
"path": "tests/dummy/app/components/no-data.hbs",
"chars": 358,
"preview": "{{!-- BEGIN-SNIPPET no-data --}}\n<div class=\"row\">\n <div class=\"col-md-2 col-md-offset-4\">\n <img src=\"images/tomster"
},
{
"path": "tests/dummy/app/components/responsive-expanded-row.hbs",
"chars": 283,
"preview": "{{!-- BEGIN-SNIPPET responsive-expanded-row --}}\n<div class=\"row\">\n <dl class=\"dl-horizontal\">\n {{#each @table.respo"
},
{
"path": "tests/dummy/app/components/responsive-table.hbs",
"chars": 1337,
"preview": "{{! BEGIN-SNIPPET responsive-table }}\n<LightTable\n @table={{this.table}}\n @height=\"65vh\"\n @responsive={{true}}\n @onA"
},
{
"path": "tests/dummy/app/components/responsive-table.js",
"chars": 1297,
"preview": "// BEGIN-SNIPPET responsive-table\nimport BaseTable from './base-table';\nimport { action } from '@ember/object';\n\nexport "
},
{
"path": "tests/dummy/app/components/row-toggle.hbs",
"chars": 303,
"preview": "{{! BEGIN-SNIPPET row-toggle }}\n<button\n class=\"row-toggle\"\n type=\"button\"\n {{on \"click\" (fn (toggle \"expanded\" @row)"
},
{
"path": "tests/dummy/app/components/rows/expandable-table.hbs",
"chars": 671,
"preview": "{{! BEGIN-SNIPPET expandable-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n <t.head\n @onColumnCl"
},
{
"path": "tests/dummy/app/components/rows/expandable-table.js",
"chars": 344,
"preview": "// BEGIN-SNIPPET expandable-table\nimport BaseTable from '../base-table';\n\nexport default class ExpandableTable extends B"
},
{
"path": "tests/dummy/app/components/rows/selectable-table.hbs",
"chars": 1329,
"preview": "{{! BEGIN-SNIPPET selectable-table }}\n<div class=\"table-actions\">\n {{#if this.hasSelection}}\n <div\n class=\"tabl"
},
{
"path": "tests/dummy/app/components/rows/selectable-table.js",
"chars": 1118,
"preview": "// BEGIN-SNIPPET selectable-table\nimport BaseTable from '../base-table';\nimport { action } from '@ember/object';\n\nexport"
},
{
"path": "tests/dummy/app/components/scrolling-table.hbs",
"chars": 2314,
"preview": "{{! BEGIN-SNIPPET scrolling-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n {{!\n In order for `so"
},
{
"path": "tests/dummy/app/components/scrolling-table.js",
"chars": 949,
"preview": "// BEGIN-SNIPPET scrolling-table\nimport BaseTable from './base-table';\nimport { action } from '@ember/object';\n\nexport d"
},
{
"path": "tests/dummy/app/components/simple-table.hbs",
"chars": 726,
"preview": "{{! BEGIN-SNIPPET simple-table }}\n<LightTable @table={{this.table}} @height=\"65vh\" as |t|>\n {{!\n In order for `sort-"
},
{
"path": "tests/dummy/app/components/simple-table.js",
"chars": 755,
"preview": "// BEGIN-SNIPPET simple-table\nimport BaseTable from './base-table';\n\nexport default class SimpleTable extends BaseTable "
},
{
"path": "tests/dummy/app/components/table-loader.hbs",
"chars": 229,
"preview": "{{!-- BEGIN-SNIPPET table-loader --}}\n<div class=\"spinner\">\n <div class=\"rect1\"></div>\n <div class=\"rect2\"></div>\n <d"
},
{
"path": "tests/dummy/app/components/user-actions.hbs",
"chars": 392,
"preview": "{{! BEGIN-SNIPPET user-actions }}\n<button\n type=\"button\"\n class=\"btn btn-sm btn-default\"\n {{on \"click\" (fn @tableActi"
},
{
"path": "tests/dummy/app/components/user-avatar.hbs",
"chars": 149,
"preview": "{{! BEGIN-SNIPPET user-avatar }}\n<img\n src={{@value}}\n class=\"user-avatar\"\n width=\"30px\"\n height=\"30px\"\n alt=\"user-"
},
{
"path": "tests/dummy/app/controllers/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "tests/dummy/app/controllers/application.js",
"chars": 182,
"preview": "import Controller from '@ember/controller';\nimport { inject as service } from '@ember/service';\n\nexport default class Ap"
},
{
"path": "tests/dummy/app/helpers/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "tests/dummy/app/helpers/classify.js",
"chars": 202,
"preview": "import { helper } from '@ember/component/helper';\nimport { classify as _classify } from '@ember/string';\n\nexport default"
},
{
"path": "tests/dummy/app/index.html",
"chars": 1248,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>Ember Light Table</title>\n <meta name=\"descript"
},
{
"path": "tests/dummy/app/models/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "tests/dummy/app/models/user.js",
"chars": 416,
"preview": "import Model, { attr } from '@ember-data/model';\n\nexport default class User extends Model {\n @attr('string')\n firstNam"
},
{
"path": "tests/dummy/app/router.js",
"chars": 814,
"preview": "import EmberRouter from '@ember/routing/router';\nimport config from 'dummy/config/environment';\n\nexport default class Ro"
},
{
"path": "tests/dummy/app/routes/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "tests/dummy/app/routes/columns/draggable.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/columns/grouped.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/columns/resizable.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/custom-row.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/custom-sort-icon.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/horizontal-scrolling.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/index.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/occlusion-rendering.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/pagination.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/sorting.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook/table-actions.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/cookbook.js",
"chars": 41,
"preview": "export { default } from './table-route';\n"
},
{
"path": "tests/dummy/app/routes/index.js",
"chars": 41,
"preview": "export { default } from './table-route';\n"
},
{
"path": "tests/dummy/app/routes/responsive.js",
"chars": 41,
"preview": "export { default } from './table-route';\n"
},
{
"path": "tests/dummy/app/routes/rows/expandable.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/rows/selectable.js",
"chars": 42,
"preview": "export { default } from '../table-route';\n"
},
{
"path": "tests/dummy/app/routes/scrolling.js",
"chars": 41,
"preview": "export { default } from './table-route';\n"
},
{
"path": "tests/dummy/app/routes/table-route.js",
"chars": 274,
"preview": "import { A } from '@ember/array';\nimport Route from '@ember/routing/route';\n\nexport default class TableRouteRoute extend"
},
{
"path": "tests/dummy/app/serializers/application.js",
"chars": 59,
"preview": "export { default } from '@ember-data/serializer/json-api';\n"
},
{
"path": "tests/dummy/app/styles/app.scss",
"chars": 4347,
"preview": "@import 'ember-power-select';\n\n$accent-color: #dd6a58;\n\n@import './loader.scss';\n@import './table.scss';\n\nhtml,\nbody {\n "
},
{
"path": "tests/dummy/app/styles/loader.scss",
"chars": 1011,
"preview": "$loader-color: #dd6a58;\n\n.spinner {\n margin: 15px auto;\n width: 50px;\n height: 50px;\n text-align: center;\n font-siz"
},
{
"path": "tests/dummy/app/styles/table.scss",
"chars": 2367,
"preview": "$border-color: #DADADA;\n\n.ember-light-table {\n width: 95%;\n margin: 0 auto;\n border-collapse: collapse;\n font-family"
},
{
"path": "tests/dummy/app/templates/application.hbs",
"chars": 5210,
"preview": "<nav class=\"navbar navbar-default\">\n <div class=\"container-fluid\">\n <div class=\"navbar-header\">\n <button\n "
},
{
"path": "tests/dummy/app/templates/columns/draggable.hbs",
"chars": 244,
"preview": "<CodePanel\n @title=\"Draggable Columns\"\n @snippets={{array\n \"draggable-table.js\"\n \"base-table.js\"\n \"draggable-"
},
{
"path": "tests/dummy/app/templates/columns/grouped.hbs",
"chars": 236,
"preview": "<CodePanel\n @title=\"Grouped Columns\"\n @snippets={{array\n \"grouped-table.js\"\n \"base-table.js\"\n \"grouped-table."
},
{
"path": "tests/dummy/app/templates/columns/resizable.hbs",
"chars": 244,
"preview": "<CodePanel\n @title=\"Resizable Columns\"\n @snippets={{array\n \"resizable-table.js\"\n \"base-table.js\"\n \"resizable-"
},
{
"path": "tests/dummy/app/templates/cookbook/client-side.hbs",
"chars": 258,
"preview": "<CodePanel\n @title=\"Client Side Search & Sort\"\n @snippets={{array\n \"client-side-table.js\"\n \"base-table.js\"\n \""
},
{
"path": "tests/dummy/app/templates/cookbook/custom-row.hbs",
"chars": 271,
"preview": "<CodePanel\n @title=\"Custom Row Component\"\n @snippets={{array\n \"custom-row-table.js\"\n \"base-table.js\"\n \"custom"
},
{
"path": "tests/dummy/app/templates/cookbook/custom-sort-icon.hbs",
"chars": 290,
"preview": "<CodePanel\n @title=\"Custom Sort Icon\"\n @snippets={{array\n \"custom-sort-icon-table.js\"\n \"base-table.js\"\n \"cust"
},
{
"path": "tests/dummy/app/templates/cookbook/horizontal-scrolling.hbs",
"chars": 280,
"preview": "<CodePanel\n @title=\"Horizontal Scrolling\"\n @snippets={{array\n \"horizontal-scrolling-table.js\"\n \"base-table.js\"\n "
},
{
"path": "tests/dummy/app/templates/cookbook/index.hbs",
"chars": 68,
"preview": "<CodePanel @title=\"Cookbook\">\n <Cookbook::IndexList/>\n</CodePanel>\n"
},
{
"path": "tests/dummy/app/templates/cookbook/occlusion-rendering.hbs",
"chars": 246,
"preview": "<CodePanel\n @title=\"Occlusion Rendering\"\n @snippets={{array\n \"occluded-table.js\"\n \"base-table.js\"\n \"occluded-"
},
{
"path": "tests/dummy/app/templates/cookbook/pagination.hbs",
"chars": 238,
"preview": "<CodePanel\n @title=\"Pagination\"\n @snippets={{array\n \"paginated-table.js\"\n \"base-table.js\"\n \"paginated-table.h"
},
{
"path": "tests/dummy/app/templates/cookbook/table-actions.hbs",
"chars": 275,
"preview": "<CodePanel\n @title=\"Table Actions\"\n @snippets={{array\n \"table-actions-table.js\"\n \"base-table.js\"\n \"table-acti"
},
{
"path": "tests/dummy/app/templates/index.hbs",
"chars": 226,
"preview": "<CodePanel\n @title=\"Simple Example\"\n @snippets={{array\n \"simple-table.js\"\n \"base-table.js\"\n \"simple-table.hbs"
},
{
"path": "tests/dummy/app/templates/responsive.hbs",
"chars": 294,
"preview": "<CodePanel\n @title=\"Responsive Example\"\n @snippets={{array\n \"responsive-table.js\"\n \"base-table.js\"\n \"responsi"
},
{
"path": "tests/dummy/app/templates/rows/expandable.hbs",
"chars": 243,
"preview": "<CodePanel\n @title=\"Expandable Rows\"\n @snippets={{array\n \"expandable-table.js\"\n \"base-table.js\"\n \"expandable-"
},
{
"path": "tests/dummy/app/templates/rows/selectable.hbs",
"chars": 260,
"preview": "<CodePanel\n @title=\"Selectable Rows\"\n @snippets={{array\n \"selectable-table.js\"\n \"base-table.js\"\n \"selectable-"
},
{
"path": "tests/dummy/app/templates/scrolling.hbs",
"chars": 235,
"preview": "<CodePanel\n @title=\"Scrolling Example\"\n @snippets={{array\n \"scrolling-table.js\"\n \"base-table.js\"\n \"scrolling-"
},
{
"path": "tests/dummy/config/ember-cli-update.json",
"chars": 451,
"preview": "{\n \"schemaVersion\": \"1.0.0\",\n \"packages\": [\n {\n \"name\": \"ember-cli\",\n \"version\": \"4.9.2\",\n \"blueprin"
},
{
"path": "tests/dummy/config/ember-try.js",
"chars": 2128,
"preview": "'use strict';\n\nconst getChannelURL = require('ember-source-channel-url');\nconst { embroiderSafe, embroiderOptimized } = "
},
{
"path": "tests/dummy/config/environment.js",
"chars": 1239,
"preview": "'use strict';\n\nmodule.exports = function (environment) {\n const ENV = {\n modulePrefix: 'dummy',\n environment,\n "
},
{
"path": "tests/dummy/config/icons.js",
"chars": 426,
"preview": "module.exports = function () {\n return {\n 'free-brands-svg-icons': ['facebook', 'github', 'twitter'],\n 'free-regu"
},
{
"path": "tests/dummy/config/optional-features.json",
"chars": 154,
"preview": "{\n \"application-template-wrapper\": false,\n \"default-async-observers\": true,\n \"jquery-integration\": false,\n \"template"
},
{
"path": "tests/dummy/config/targets.js",
"chars": 157,
"preview": "'use strict';\n\nconst browsers = [\n 'last 1 Chrome versions',\n 'last 1 Firefox versions',\n 'last 1 Safari versions',\n]"
},
{
"path": "tests/dummy/mirage/config.js",
"chars": 1581,
"preview": "import { discoverEmberDataModels } from 'ember-cli-mirage';\nimport { createServer } from 'miragejs';\nimport { A as ember"
},
{
"path": "tests/dummy/mirage/factories/user.js",
"chars": 885,
"preview": "/*\n This is an example factory definition.\n\n Create more files in this directory to define additional factories.\n*/\nim"
},
{
"path": "tests/dummy/mirage/models/user.js",
"chars": 68,
"preview": "import { Model } from 'miragejs';\n\nexport default Model.extend({});\n"
},
{
"path": "tests/dummy/mirage/scenarios/default.js",
"chars": 179,
"preview": "export default function (server) {\n // Seed your development database using your factories. This\n // data will not be "
},
{
"path": "tests/dummy/mirage/serializers/application.js",
"chars": 92,
"preview": "import { JSONAPISerializer } from 'miragejs';\n\nexport default JSONAPISerializer.extend({});\n"
},
{
"path": "tests/dummy/public/robots.txt",
"chars": 51,
"preview": "# http://www.robotstxt.org\nUser-agent: *\nDisallow:\n"
},
{
"path": "tests/helpers/has-class.js",
"chars": 171,
"preview": "export default function hasClass(elem, cls) {\n return [...elem.classList]\n .filter((cssClass) => cssClass === cls)\n "
},
{
"path": "tests/helpers/index.js",
"chars": 1269,
"preview": "import {\n setupApplicationTest as upstreamSetupApplicationTest,\n setupRenderingTest as upstreamSetupRenderingTest,\n s"
},
{
"path": "tests/helpers/responsive.js",
"chars": 1701,
"preview": "/* eslint-disable */\n\nimport { A } from '@ember/array';\nimport { classify } from '@ember/string';\nimport { computed } fr"
},
{
"path": "tests/helpers/table-columns.js",
"chars": 2376,
"preview": "export default [\n {\n label: 'Avatar',\n valuePath: 'avatar',\n width: '60px',\n sortable: false,\n cellCompo"
},
{
"path": "tests/index.html",
"chars": 1170,
"preview": "<!DOCTYPE html>\n<html>\n <head>\n <meta charset=\"utf-8\">\n <title>Dummy Tests</title>\n <meta name=\"description\" c"
},
{
"path": "tests/integration/.gitkeep",
"chars": 0,
"preview": ""
},
{
"path": "tests/integration/components/light-table/cells/base-test.js",
"chars": 2111,
"preview": "import { module, test } from 'qunit';\nimport { setupRenderingTest } from 'ember-qunit';\nimport { render } from '@ember/t"
},
{
"path": "tests/integration/components/light-table/columns/base-test.js",
"chars": 668,
"preview": "import { module, test } from 'qunit';\nimport { setupRenderingTest } from 'ember-qunit';\nimport { render } from '@ember/t"
},
{
"path": "tests/integration/components/light-table-occlusion-test.js",
"chars": 8969,
"preview": "import { setupRenderingTest } from 'ember-qunit';\nimport {\n render,\n findAll,\n find,\n click,\n triggerEvent,\n} from "
},
{
"path": "tests/integration/components/light-table-test.js",
"chars": 10898,
"preview": "import { setupRenderingTest } from 'ember-qunit';\nimport {\n render,\n findAll,\n find,\n click,\n triggerEvent,\n} from "
},
{
"path": "tests/integration/components/lt-body-occlusion-test.js",
"chars": 6458,
"preview": "import {\n click,\n find,\n triggerEvent,\n settled,\n render,\n} from '@ember/test-helpers';\nimport { module, test } fro"
},
{
"path": "tests/integration/components/lt-body-test.js",
"chars": 9905,
"preview": "import {\n click,\n findAll,\n find,\n triggerEvent,\n render,\n} from '@ember/test-helpers';\nimport { module, test } fro"
},
{
"path": "tests/integration/components/lt-column-resizer-test.js",
"chars": 760,
"preview": "import { module, test } from 'qunit';\nimport { setupRenderingTest } from 'ember-qunit';\nimport { render } from '@ember/t"
}
]
// ... and 16 more files (download for full content)
About this extraction
This page contains the full source code of the offirgolan/ember-light-table GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 216 files (289.4 KB), approximately 84.6k tokens, and a symbol index with 180 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.