├── .gitignore ├── docs ├── favicon.png ├── vgt-logo.png ├── hero-image.png ├── vgt-logo-2x.png ├── assets │ ├── img │ │ └── search.83621669.svg │ └── js │ │ ├── 4.751cd6eb.js │ │ ├── 5.f9c81e08.js │ │ ├── 24.e026c190.js │ │ ├── 20.c7c2a7a6.js │ │ ├── 23.8a55ba7a.js │ │ ├── 17.78aa3f39.js │ │ ├── 21.2dfef136.js │ │ ├── 22.ec06531f.js │ │ ├── 38.fc6dd42f.js │ │ ├── 16.b0065a94.js │ │ ├── 8.f51d7e4e.js │ │ ├── 7.3f6cd7fb.js │ │ ├── 13.941a2941.js │ │ ├── 19.d6dddf3d.js │ │ ├── 11.c8a5abb4.js │ │ ├── 14.00a22c84.js │ │ ├── 18.23bc9f91.js │ │ ├── 10.54b5e228.js │ │ ├── 9.e00df4e4.js │ │ ├── 12.36cf977b.js │ │ ├── 15.2193695d.js │ │ ├── 6.9355beb5.js │ │ └── 3.e88f9927.js └── 404.html ├── vp-docs ├── .vuepress │ ├── theme │ │ ├── index.js │ │ ├── layouts │ │ │ └── Layout.vue │ │ └── components │ │ │ ├── UserBitAd.vue │ │ │ ├── CarbonAds.vue │ │ │ └── Banner.vue │ ├── public │ │ ├── favicon.png │ │ ├── vgt-logo.png │ │ ├── hero-image.png │ │ └── vgt-logo-2x.png │ ├── dist │ │ ├── vgt-table.regular.png │ │ ├── assets │ │ │ ├── img │ │ │ │ └── search.83621669.svg │ │ │ └── js │ │ │ │ ├── 15.125b08dc.js │ │ │ │ ├── 16.9e087e7c.js │ │ │ │ ├── 17.0ee802cb.js │ │ │ │ ├── 21.6ce211a6.js │ │ │ │ ├── 19.5eb669bb.js │ │ │ │ ├── 18.57facccb.js │ │ │ │ ├── 20.6c61e0f6.js │ │ │ │ ├── 2.bc66dc77.js │ │ │ │ └── 4.df9755ec.js │ │ ├── 404.html │ │ └── index.html │ ├── enhanceApp.js │ ├── components │ │ ├── other-projects.vue │ │ ├── basic-table.vue │ │ ├── rtl-table.vue │ │ ├── line-numbers-table.vue │ │ ├── fixed-header.vue │ │ ├── custom-row.vue │ │ ├── theme-example.vue │ │ ├── search-demo.vue │ │ ├── external-query.vue │ │ ├── checkbox-table.vue │ │ ├── pagination-table.vue │ │ ├── before-after-columns.vue │ │ ├── grouped-table.vue │ │ ├── action-slot-table.vue │ │ ├── grouped-custom-span.vue │ │ └── grouped-custom.vue │ └── config.js ├── guide │ ├── style-configuration │ │ ├── sass.md │ │ ├── README.md │ │ └── style-classes.md │ ├── configuration │ │ ├── sort-options.md │ │ ├── column-filter-options.md │ │ ├── search-options.md │ │ ├── README.md │ │ └── table-events.md │ ├── advanced │ │ ├── checkbox-table.md │ │ ├── remote-workflow.md │ │ └── grouped-table.md │ └── README.md └── README.md ├── .npmignore ├── README └── images │ ├── vgt-table.png │ ├── vgt-table.regular.png │ ├── vgt-table.advanced.png │ ├── vgt-table.checkbox.png │ ├── vgt-table.condensed.png │ ├── vgt-table.nocturnal.png │ └── vgt-table.black-rhino.png ├── src ├── styles │ ├── _condensed.scss │ ├── _striped.scss │ ├── _wrap.scss │ ├── _bordered.scss │ ├── nocturnal │ │ ├── _overrides.scss │ │ └── nocturnal.scss │ ├── _loading.scss │ ├── _rtl.scss │ ├── black-rhino │ │ ├── _overrides.scss │ │ └── black-rhino.scss │ ├── _table.scss │ ├── polar-bear │ │ ├── _overrides.scss │ │ └── polar-bear.scss │ ├── style.scss │ ├── _input.scss │ ├── _variables.scss │ ├── _utils.scss │ ├── _compact.scss │ ├── _control-bar.scss │ ├── _table-th.scss │ └── _table-footer.scss ├── components │ ├── types │ │ ├── decimal.js │ │ ├── percentage.js │ │ ├── index.js │ │ ├── boolean.js │ │ ├── number.js │ │ ├── date.js │ │ └── default.js │ ├── utils │ │ ├── constants.js │ │ └── sort.js │ ├── VgtGlobalSearch.vue │ ├── pagination │ │ └── VgtPaginationPageInfo.vue │ └── VgtHeaderRow.vue └── index.js ├── test ├── unit │ ├── .eslintrc │ ├── specs │ │ ├── types │ │ │ ├── decimal.spec.js │ │ │ ├── percentage.spec.js │ │ │ ├── number.spec.js │ │ │ ├── date.spec.js │ │ │ └── default.spec.js │ │ ├── Pagination.spec.js │ │ └── Table.spec.js │ ├── index.js │ └── karma.conf.js └── e2e │ ├── specs │ └── test.js │ ├── custom-assertions │ └── elementCount.js │ ├── runner.js │ └── nightwatch.conf.js ├── dev ├── index.html ├── main.js └── grouped-table.vue ├── .github └── issue_template.md ├── deploy-docs.sh ├── .eslintrc ├── bili.config.js ├── LICENSE ├── package.json └── CODE_OF_CONDUCT.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | node_modules/ 4 | -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/docs/favicon.png -------------------------------------------------------------------------------- /docs/vgt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/docs/vgt-logo.png -------------------------------------------------------------------------------- /docs/hero-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/docs/hero-image.png -------------------------------------------------------------------------------- /docs/vgt-logo-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/docs/vgt-logo-2x.png -------------------------------------------------------------------------------- /vp-docs/.vuepress/theme/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extend: '@vuepress/theme-default' 3 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .DS_Store 3 | node_modules/ 4 | *.log 5 | dev 6 | src 7 | docs 8 | vp-docs 9 | .babelrc -------------------------------------------------------------------------------- /README/images/vgt-table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/README/images/vgt-table.png -------------------------------------------------------------------------------- /README/images/vgt-table.regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/README/images/vgt-table.regular.png -------------------------------------------------------------------------------- /README/images/vgt-table.advanced.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/README/images/vgt-table.advanced.png -------------------------------------------------------------------------------- /README/images/vgt-table.checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/README/images/vgt-table.checkbox.png -------------------------------------------------------------------------------- /README/images/vgt-table.condensed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/README/images/vgt-table.condensed.png -------------------------------------------------------------------------------- /README/images/vgt-table.nocturnal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/README/images/vgt-table.nocturnal.png -------------------------------------------------------------------------------- /vp-docs/.vuepress/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/vp-docs/.vuepress/public/favicon.png -------------------------------------------------------------------------------- /vp-docs/.vuepress/public/vgt-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/vp-docs/.vuepress/public/vgt-logo.png -------------------------------------------------------------------------------- /README/images/vgt-table.black-rhino.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/README/images/vgt-table.black-rhino.png -------------------------------------------------------------------------------- /vp-docs/.vuepress/public/hero-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/vp-docs/.vuepress/public/hero-image.png -------------------------------------------------------------------------------- /vp-docs/.vuepress/public/vgt-logo-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/vp-docs/.vuepress/public/vgt-logo-2x.png -------------------------------------------------------------------------------- /src/styles/_condensed.scss: -------------------------------------------------------------------------------- 1 | .vgt-table{ 2 | &.condensed td, &.condensed th.vgt-row-header{ 3 | padding: .4em .4em .4em .4em; 4 | } 5 | } -------------------------------------------------------------------------------- /src/styles/_striped.scss: -------------------------------------------------------------------------------- 1 | .vgt-table{ 2 | &.striped tbody tr:nth-of-type(odd) { 3 | background-color: rgba(51, 68, 109, 0.03); 4 | } 5 | } -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/vgt-table.regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xaksis/vue-good-table/HEAD/vp-docs/.vuepress/dist/vgt-table.regular.png -------------------------------------------------------------------------------- /src/styles/_wrap.scss: -------------------------------------------------------------------------------- 1 | .vgt-wrap{ 2 | position: relative; 3 | } 4 | .vgt-fixed-header{ 5 | position: absolute; 6 | z-index: 10; 7 | overflow-x: auto; 8 | } -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/styles/_bordered.scss: -------------------------------------------------------------------------------- 1 | .vgt-table{ 2 | &.bordered td, &.bordered th { 3 | border: 1px solid $border-color; 4 | } 5 | &.bordered th.vgt-row-header{ 6 | border-bottom: 3px solid $border-color; 7 | } 8 | } -------------------------------------------------------------------------------- /docs/assets/img/search.83621669.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/img/search.83621669.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/15.125b08dc.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[15],{195:function(t,n,e){"use strict";e.r(n);var s=e(0),c=Object(s.a)({},function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"content"})},[],!1,null,null,null);n.default=c.exports}}]); -------------------------------------------------------------------------------- /src/components/types/decimal.js: -------------------------------------------------------------------------------- 1 | import number from './number'; 2 | 3 | const decimal = Object.assign({}, number); 4 | 5 | decimal.format = function (v) { 6 | if (v === undefined || v === null) return ''; 7 | return parseFloat(Math.round(v * 100) / 100).toFixed(2); 8 | }; 9 | 10 | export default decimal; 11 | -------------------------------------------------------------------------------- /src/components/types/percentage.js: -------------------------------------------------------------------------------- 1 | import number from './number'; 2 | 3 | const percentage = Object.assign({}, number); 4 | 5 | percentage.format = function (v) { 6 | if (v === undefined || v === null) return ''; 7 | return `${parseFloat(v * 100).toFixed(2)}%`; 8 | }; 9 | 10 | export default percentage; 11 | -------------------------------------------------------------------------------- /vp-docs/guide/style-configuration/sass.md: -------------------------------------------------------------------------------- 1 | # Sass 2 | 3 | Vue-Good-Table's styling is written in Sass. The source files are made available as part of the npm dependency. 4 | 5 | **Vue-Good-Table's root Sass file:** 6 | 7 | ```scss 8 | @import "../node_modules/vue-good-table/src/styles/style.scss"; 9 | ``` 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/components/types/index.js: -------------------------------------------------------------------------------- 1 | import * as date from './date'; 2 | import * as decimal from './decimal'; 3 | import * as number from './number'; 4 | import * as percentage from './percentage'; 5 | import * as boolean from './boolean'; 6 | 7 | export default { 8 | date, 9 | decimal, 10 | number, 11 | percentage, 12 | boolean, 13 | }; 14 | -------------------------------------------------------------------------------- /src/styles/nocturnal/_overrides.scss: -------------------------------------------------------------------------------- 1 | $thead-bg-color-1: #2C394F; 2 | $thead-bg-color-2: #2C394F; 3 | $chevron-color: lighten($thead-bg-color-1, 10%); 4 | 5 | $text-color: #C7CED8; 6 | $secondary-text-color: #8290A7 ; 7 | $border-color: #435169; 8 | $input-border-color: $border-color; 9 | 10 | $table-bg: #324057; 11 | $highlight-color: #445168; -------------------------------------------------------------------------------- /vp-docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- 1 | import VueGoodTable from '../../src'; 2 | 3 | export default ({ 4 | Vue, // the version of Vue being used in the VuePress app 5 | options, // the options for the root Vue instance 6 | router, // the router instance for the app 7 | siteData, // site metadata 8 | }) => { 9 | // ...apply enhancements to the app 10 | Vue.use(VueGoodTable); 11 | } -------------------------------------------------------------------------------- /src/styles/_loading.scss: -------------------------------------------------------------------------------- 1 | .vgt-loading{ 2 | position: absolute; 3 | width: 100%; 4 | z-index: 10; 5 | margin-top: 117px; 6 | &__content{ 7 | background-color: lighten($link-color, 25%); 8 | color: $link-color; 9 | padding: 7px 30px; 10 | border-radius: 3px; 11 | } 12 | } 13 | 14 | .vgt-inner-wrap.is-loading{ 15 | opacity: 0.5; 16 | pointer-events: none; 17 | } -------------------------------------------------------------------------------- /dev/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-good-table 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /dev/main.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line import/no-extraneous-dependencies 2 | import Vue from 'vue'; 3 | import App from './App.vue'; 4 | // import VueGoodTable from '../dist/vue-good-table.esm'; 5 | // import '../dist/vue-good-table.css'; 6 | import VueGoodTable from '../src'; 7 | 8 | Vue.use(VueGoodTable); 9 | 10 | Vue.config.productionTip = false; 11 | 12 | /* eslint-disable no-new */ 13 | new Vue({ 14 | el: '#app', 15 | render: h => h(App), 16 | }); 17 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import VueGoodTable from './components/Table.vue'; 2 | 3 | const VueGoodTablePlugin = { 4 | install(Vue, options) { 5 | Vue.component(VueGoodTable.name, VueGoodTable); 6 | }, 7 | }; 8 | 9 | // Automatic installation if Vue has been added to the global scope. 10 | if (typeof window !== 'undefined' && window.Vue) { 11 | window.Vue.use(VueGoodTablePlugin); 12 | } 13 | 14 | export default VueGoodTablePlugin; 15 | export { VueGoodTable }; 16 | -------------------------------------------------------------------------------- /src/styles/_rtl.scss: -------------------------------------------------------------------------------- 1 | .vgt-wrap.rtl{ 2 | direction: rtl; 3 | 4 | .vgt-table{ 5 | thead th, &.condensed thead th { 6 | padding-left: 1.5em; 7 | padding-right: .75em; 8 | } 9 | th.sorting:after, 10 | th.sorting-asc:after{ 11 | margin-right: 5px; 12 | margin-left: 0px; 13 | } 14 | 15 | th.sortable:after, 16 | th.sortable:before { 17 | right: inherit; 18 | left: 6px; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/components/utils/constants.js: -------------------------------------------------------------------------------- 1 | const DEFAULT_SORT_TYPE = 'asc'; 2 | const SORT_TYPES = { 3 | Ascending: 'asc', 4 | Descending: 'desc', 5 | None: 'none', 6 | }; 7 | 8 | const PAGINATION_MODES = { 9 | Pages: 'pages', 10 | Records: 'records', 11 | }; 12 | const DEFAULT_ROWS_PER_PAGE_DROPDOWN = [10, 20, 30, 40, 50]; 13 | 14 | export { 15 | DEFAULT_SORT_TYPE, 16 | SORT_TYPES, 17 | 18 | PAGINATION_MODES, 19 | DEFAULT_ROWS_PER_PAGE_DROPDOWN, 20 | }; 21 | -------------------------------------------------------------------------------- /test/unit/specs/types/decimal.spec.js: -------------------------------------------------------------------------------- 1 | import decimalType from '@/components/types/decimal' 2 | import { expect } from 'chai' 3 | 4 | describe('decimal type', () => { 5 | describe('format', () => { 6 | it('should format always with two decimals', () => { 7 | expect(decimalType.format('1')).to.equal('1.00') 8 | }) 9 | 10 | it('should cut at two decimals', () => { 11 | expect(decimalType.format('3.14159265359')).to.equal('3.14') 12 | }) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /src/styles/black-rhino/_overrides.scss: -------------------------------------------------------------------------------- 1 | $thead-bg-color-1: #4c5c79; 2 | $thead-bg-color-2: #4e5d7c; 3 | 4 | $chevron-color: lighten($thead-bg-color-1, 10%); 5 | 6 | $text-color: #dae2f0; 7 | $text-color-td: rgb(73, 81, 94); 8 | $text-shadow-color: lighten(#2C394F, 10%); 9 | 10 | $secondary-text-color: rgb(152, 165, 185) ; 11 | $border-color: #435169; 12 | $border-color-td: #bbc5d6; 13 | 14 | $input-border-color: transparent; 15 | $input-bg: #34445f; 16 | 17 | $table-bg: #dfe5ee; 18 | $highlight-color:#fff; -------------------------------------------------------------------------------- /docs/assets/js/4.751cd6eb.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[4],{449:function(t,e,n){},493:function(t,e,n){"use strict";n(449)},533:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(493),n(4)),p=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=p.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/5.f9c81e08.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[5],{450:function(e,t,c){},494:function(e,t,c){"use strict";c(450)},531:function(e,t,c){"use strict";c.r(t);var i={name:"CodeBlock",props:{title:{type:String,required:!0},active:{type:Boolean,default:!1}}},n=(c(494),c(4)),s=Object(n.a)(i,(function(){var e=this.$createElement;return(this._self._c||e)("div",{staticClass:"theme-code-block",class:{"theme-code-block__active":this.active}},[this._t("default")],2)}),[],!1,null,"6d04095e",null);t.default=s.exports}}]); -------------------------------------------------------------------------------- /src/styles/_table.scss: -------------------------------------------------------------------------------- 1 | table.vgt-table{ 2 | font-size: 16px; 3 | border-collapse: collapse; 4 | background-color: $table-bg; 5 | width: 100%; 6 | max-width: 100%; 7 | table-layout: auto; 8 | border: 1px solid $border-color; 9 | & td { 10 | padding: .75em .75em .75em .75em; 11 | vertical-align: top; 12 | border-bottom: 1px solid $border-color; 13 | color: $text-color; 14 | } 15 | & tr.clickable { 16 | cursor: pointer; 17 | &:hover{ 18 | background-color: $highlight-color; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.config.productionTip = false 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('../../src', true, /^\.\/(?!index(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/specs/types/percentage.spec.js: -------------------------------------------------------------------------------- 1 | import percentageType from '@/components/types/percentage' 2 | 3 | describe('percentage type', () => { 4 | describe('format', () => { 5 | it('should return the percentage formatted answer if passed over 100%', () => { 6 | var x = '2' 7 | expect(percentageType.format(x)).to.equal('200.00%') 8 | }) 9 | 10 | it('should return the percentage formatted answer if passed under 50%', () => { 11 | var x = '.5' 12 | expect(percentageType.format(x)).to.equal('50.00%') 13 | }) 14 | }) 15 | }) 16 | -------------------------------------------------------------------------------- /src/styles/polar-bear/_overrides.scss: -------------------------------------------------------------------------------- 1 | $thead-bg-color-1: #E4EBF3; 2 | $thead-bg-color-2: #E4EBF3; 3 | $thead-bg-color-3: #f7fafc; 4 | 5 | $header-color: darken(#8395aa, 10%); 6 | $text-color: #394567; 7 | $link-color: #5e72e4; 8 | $focus-color: #4D96FB; 9 | $text-color-td: #525f7f; 10 | $text-shadow-color: lighten(#2C394F, 10%); 11 | 12 | $secondary-text-color: rgb(152, 165, 185) ; 13 | $border-color: #e3e8ee; 14 | $border-color-td: #E4EBF3; 15 | 16 | $input-border-color: transparent; 17 | $input-bg: #34445f; 18 | 19 | $table-bg: #FFFFFF; 20 | $highlight-color:#fff; 21 | $white: #FFFFFF; -------------------------------------------------------------------------------- /vp-docs/.vuepress/theme/layouts/Layout.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | -------------------------------------------------------------------------------- /src/styles/style.scss: -------------------------------------------------------------------------------- 1 | @import './striped'; 2 | 3 | // base table styles 4 | @import './variables'; 5 | @import './utils'; 6 | @import './wrap'; 7 | @import './table'; 8 | @import './table-th'; 9 | @import './input'; 10 | @import './loading'; 11 | 12 | // table enhancements 13 | @import './bordered'; 14 | @import './rtl'; 15 | @import './condensed'; 16 | @import './compact'; 17 | 18 | // controls on top 19 | @import './control-bar'; 20 | 21 | // table footer 22 | @import './table-footer'; 23 | 24 | //themes 25 | @import './nocturnal/nocturnal'; 26 | @import './black-rhino/black-rhino'; 27 | @import './polar-bear/polar-bear'; 28 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | ### Issue Type (delete the irrelevant ones) 2 | 3 | - [x] Bug 4 | - [x] Enhancement Request 5 | - [x] Question 6 | 7 | ### Specs 8 | What version are you using? 9 | 10 | What browser? 11 | 12 | ### Expected Behavior 13 | What did you expect to happen? 14 | 15 | ### Actual Behavior 16 | What actually happened? 17 | 18 | ### Steps to Reproduce the Problem 19 | Please detail your steps here 20 | 21 | 1. 22 | 1. 23 | 1. 24 | 25 | ### jsfiddle 26 | If you provide a jsfiddle reproducing the issue, it'll be addressed much faster. 27 | you can use [this as base](https://jsfiddle.net/aks9800/57a2a4ce/) 28 | 29 | -------------------------------------------------------------------------------- /deploy-docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # abort on errors 4 | set -e 5 | 6 | # build 7 | npm run docs:build 8 | 9 | # navigate into the build output directory 10 | cd docs/.vuepress/dist 11 | 12 | # if you are deploying to a custom domain 13 | # echo 'www.example.com' > CNAME 14 | 15 | git init 16 | git add -A 17 | git commit -m 'deploy' 18 | 19 | # if you are deploying to https://.github.io 20 | # git push -f git@github.com:/.github.io.git master 21 | 22 | # if you are deploying to https://.github.io/ 23 | git push -f git@github.com:xaksis/vue-good-table.git master:gh-pages 24 | 25 | cd - -------------------------------------------------------------------------------- /src/components/types/boolean.js: -------------------------------------------------------------------------------- 1 | import def from './default'; 2 | 3 | const boolean = Object.assign({}, def); 4 | 5 | boolean.isRight = true; 6 | 7 | boolean.filterPredicate = function (rowval, filter) { 8 | return boolean.compare(rowval, filter) === 0; 9 | }; 10 | 11 | 12 | boolean.compare = function (x, y) { 13 | function cook(d) { 14 | if (typeof d === 'boolean') return d ? 1 : 0; 15 | if (typeof d === 'string') return d === 'true' ? 1 : 0; 16 | return -Infinity; 17 | } 18 | 19 | x = cook(x); 20 | y = cook(y); 21 | if (x < y) return -1; 22 | if (x > y) return 1; 23 | return 0; 24 | }; 25 | 26 | export default boolean; 27 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/styles/_input.scss: -------------------------------------------------------------------------------- 1 | 2 | .vgt-input, .vgt-select{ 3 | width: 100%; 4 | height: 32px; 5 | line-height: 1; 6 | display: block; 7 | font-size: 14px; 8 | font-weight: normal; 9 | padding: 6px 12px; 10 | color: $text-color; 11 | border-radius: 4px; 12 | box-sizing: border-box; 13 | background-image: none; 14 | background-color: #fff; 15 | border: 1px solid $input-border-color; 16 | transition: border-color .2s cubic-bezier(.645,.045,.355,1); 17 | &::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 18 | color: $text-color; 19 | opacity: 0.3; /* Firefox */ 20 | } 21 | &:focus{ 22 | outline: none; 23 | border-color: $link-color; 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/styles/_variables.scss: -------------------------------------------------------------------------------- 1 | 2 | // grey ramp 3 | $base-grey: #DCDFE6 !default; 4 | $light-grey: #E4E7ED !default; 5 | $lighter-grey: #EBEEF5 !default; 6 | $extra-light: #F2F6FC !default; 7 | 8 | $table-bg: #FFFFFF !default; 9 | $text-color: #606266 !default; 10 | $secondary-text-color: #909399 !default; 11 | $input-border-color: $base-grey !default; 12 | $border-color: $base-grey !default; 13 | $highlight-color: #F1F5FD !default; 14 | 15 | $thead-bg-color-1: #F4F5F8 !default; 16 | $thead-bg-color-2: #F1F3F6 !default; 17 | // $chevron-color: darken($thead-bg-color-1, 12%); 18 | $chevron-color: #606266; 19 | 20 | // link 21 | $link-color: #409eff; 22 | $notify-bg-color: #fdf9e8; 23 | $notify-fg-color: #b38d28; -------------------------------------------------------------------------------- /docs/assets/js/24.e026c190.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[24],{514:function(t,e,s){"use strict";s.r(e);var n=["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],o={methods:{getMsg:function(){return n[Math.floor(Math.random()*n.length)]}}},i=s(4),h=Object(i.a)(o,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"theme-container"},[e("div",{staticClass:"theme-default-content"},[e("h1",[this._v("404")]),this._v(" "),e("blockquote",[this._v(this._s(this.getMsg()))]),this._v(" "),e("RouterLink",{attrs:{to:"/"}},[this._v("\n Take me home.\n ")])],1)])}),[],!1,null,null,null);e.default=h.exports}}]); -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "airbnb", 4 | "plugin:vue/base" 5 | ], 6 | "rules": { 7 | "func-names": ["error", "never"], 8 | "no-shadow": "off", 9 | "no-unused-vars": "off", 10 | "consistent-return": "off", 11 | "no-param-reassign": "off", 12 | "no-plusplus": "off", 13 | "import/no-unresolved": "off", 14 | "import/extensions": "off", 15 | "no-continue": "off", 16 | "comma-dangle": ["error", { 17 | "arrays": "always-multiline", 18 | "objects": "always-multiline", 19 | "imports": "always-multiline", 20 | "exports": "always-multiline", 21 | "functions": "never" 22 | }] 23 | }, 24 | "globals": { 25 | "_": false, 26 | "moment": false 27 | } 28 | } -------------------------------------------------------------------------------- /src/components/types/number.js: -------------------------------------------------------------------------------- 1 | import def from './default'; 2 | 3 | const number = Object.assign({}, def); 4 | 5 | number.isRight = true; 6 | 7 | number.filterPredicate = function (rowval, filter) { 8 | return number.compare(rowval, filter) === 0; 9 | }; 10 | 11 | 12 | number.compare = function (x, y) { 13 | function cook(d) { 14 | // if d is null or undefined we give it the smallest 15 | // possible value 16 | if (d === undefined || d === null) return -Infinity; 17 | return d.indexOf('.') >= 0 ? parseFloat(d) : parseInt(d, 10); 18 | } 19 | 20 | x = typeof x === 'number' ? x : cook(x); 21 | y = typeof y === 'number' ? y : cook(y); 22 | if (x < y) return -1; 23 | if (x > y) return 1; 24 | return 0; 25 | }; 26 | 27 | export default number; 28 | -------------------------------------------------------------------------------- /vp-docs/guide/style-configuration/README.md: -------------------------------------------------------------------------------- 1 | # Themes 2 | 3 | ## Default 4 | ```html 5 | 8 | 9 | ``` 10 | 11 | 12 | ## Polar-bear 13 | ```html 14 | 18 | 19 | ``` 20 | 21 | 22 | 23 | ## Black-rhino 24 | ```html 25 | 29 | 30 | ``` 31 | 32 | 33 | 34 | ## Nocturnal 35 | 36 | ```html 37 | 41 | 42 | ``` 43 | -------------------------------------------------------------------------------- /bili.config.js: -------------------------------------------------------------------------------- 1 | const { version } = require('./package'); 2 | 3 | const banner = `/** 4 | * vue-good-table v${version} 5 | * (c) 2018-present xaksis 6 | * https://github.com/xaksis/vue-good-table 7 | * Released under the MIT License. 8 | */ 9 | `; 10 | 11 | module.exports = { 12 | banner, 13 | output: { 14 | fileName: (context, defaultFileName) => { 15 | if (context.format === 'umd' || context.format === 'umd-min') { 16 | return 'vue-good-table[min].js'; 17 | } 18 | return 'vue-good-table.[format].js'; 19 | }, 20 | moduleName: 'vue-good-table', 21 | format: [ 22 | 'cjs', 23 | 'es', 24 | 'umd', 25 | 'umd-min', 26 | ], 27 | }, 28 | plugins: { 29 | commonjs: true, 30 | vue: { 31 | css: false, 32 | }, 33 | }, 34 | bundleNodeModules: true, 35 | }; 36 | -------------------------------------------------------------------------------- /vp-docs/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | heroImage: /hero-image.png 4 | actionText: Get Started → 5 | actionLink: /guide/ 6 | footer: MIT Licensed | Copyright © 2018-present xaksis 7 | --- 8 | 9 |
10 |
11 |

Get Started Quickly

12 |

Get features like sorting / column filtering / paging with minimal setup.

13 |
14 |
15 |

Customizable

16 |

Easily customize anything from table cells to column headers.

17 |
18 |
19 |

Advanced Features

20 |

Leverage checkbox table, grouped rows and remote workflow for your table.

21 |
22 |
23 | 24 | 25 | 26 | 27 | 33 | -------------------------------------------------------------------------------- /src/styles/_utils.scss: -------------------------------------------------------------------------------- 1 | /* Utility styles 2 | ************************************************/ 3 | .vgt-right-align{ 4 | text-align: right; 5 | } 6 | 7 | .vgt-left-align{ 8 | text-align: left; 9 | } 10 | 11 | .vgt-center-align{ 12 | text-align: center; 13 | } 14 | 15 | .vgt-pull-left{ 16 | float: left !important; 17 | } 18 | 19 | .vgt-pull-right{ 20 | float: right !important; 21 | } 22 | 23 | .vgt-clearfix::after { 24 | display: block; 25 | content: ""; 26 | clear: both; 27 | } 28 | 29 | .vgt-responsive { 30 | width: 100%; 31 | overflow-x: auto; 32 | position: relative; 33 | } 34 | 35 | .vgt-text-disabled{ 36 | color: $secondary-text-color; 37 | } 38 | 39 | .sr-only { 40 | clip: rect(0 0 0 0); 41 | clip-path: inset(50%); 42 | height: 1px; 43 | overflow: hidden; 44 | position: absolute; 45 | white-space: nowrap; 46 | width: 1px; 47 | } -------------------------------------------------------------------------------- /src/styles/_compact.scss: -------------------------------------------------------------------------------- 1 | /*responsive compactMode*/ 2 | @media (max-width: 576px) { 3 | .vgt-compact { 4 | * { 5 | box-sizing: border-box; 6 | } 7 | 8 | tbody, 9 | tr, 10 | td { 11 | display: block; 12 | width: 100%; 13 | } 14 | thead { 15 | display: none; 16 | } 17 | tr { 18 | margin-bottom: 15px; 19 | } 20 | td { 21 | text-align: right; 22 | position: relative; 23 | &:before { 24 | content: attr(data-label); 25 | position: relative; 26 | float: left; 27 | left: 0; 28 | width: 40%; 29 | padding-left: 10px; 30 | font-weight: bold; 31 | text-align: left; 32 | } 33 | } 34 | th.line-numbers { 35 | width: 100% !important; 36 | display: block; 37 | padding: 0.3em 1em !important; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/assets/js/20.c7c2a7a6.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[20],{446:function(e,t,n){},490:function(e,t,n){"use strict";n(446)},528:function(e,t,n){"use strict";n.r(t);var a={name:"rtl-table",data:function(){return{columns:[{label:"Name",field:"name",filterOptions:{enabled:!1}},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(n(490),n(4)),r=Object(o.a)(a,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,rtl:!0}})],1)}),[],!1,null,null,null);t.default=r.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/23.8a55ba7a.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[23],{432:function(t,e,s){},476:function(t,e,s){"use strict";s(432)},542:function(t,e,s){"use strict";s.r(e);s(476);var a=s(4),r=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("div",{staticClass:"features"},[s("div",{staticClass:"feature"},[s("h2",[t._v("Get Started Quickly")]),t._v(" "),s("p",[t._v("Get features like sorting / column filtering / paging with minimal setup.")])]),t._v(" "),s("div",{staticClass:"feature"},[s("h2",[t._v("Customizable")]),t._v(" "),s("p",[t._v("Easily customize anything from table cells to column headers.")])]),t._v(" "),s("div",{staticClass:"feature"},[s("h2",[t._v("Advanced Features")]),t._v(" "),s("p",[t._v("Leverage checkbox table, grouped rows and remote workflow for your table.")])])]),t._v(" "),s("other-projects")],1)}),[],!1,null,null,null);e.default=r.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/17.78aa3f39.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[17],{444:function(e,t,n){},488:function(e,t,n){"use strict";n(444)},526:function(e,t,n){"use strict";n.r(t);var a={name:"line-numbers-table",data:function(){return{columns:[{label:"Name",field:"name",filterOptions:{enabled:!1}},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(n(488),n(4)),r=Object(o.a)(a,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,lineNumbers:!0}})],1)}),[],!1,null,null,null);t.default=r.exports}}]); -------------------------------------------------------------------------------- /src/components/types/date.js: -------------------------------------------------------------------------------- 1 | import { format, parse, isValid, compareAsc } from 'date-fns'; 2 | import def from './default'; 3 | 4 | const date = Object.assign({}, def); 5 | 6 | date.isRight = true; 7 | 8 | date.compare = function (x, y, column) { 9 | function cook(d) { 10 | if (column && column.dateInputFormat) { 11 | return parse(`${d}`, `${column.dateInputFormat}`, new Date()); 12 | } 13 | return d; 14 | } 15 | x = cook(x); 16 | y = cook(y); 17 | if (!isValid(x)) { 18 | return -1; 19 | } 20 | if (!isValid(y)) { 21 | return 1; 22 | } 23 | return compareAsc(x, y); 24 | }; 25 | 26 | date.format = function (v, column) { 27 | if (v === undefined || v === null) return ''; 28 | // convert to date 29 | const date = parse(v, column.dateInputFormat, new Date()); 30 | if (isValid(date)) { 31 | return format(date, column.dateOutputFormat); 32 | } 33 | console.error(`Not a valid date: "${v}"`); 34 | return null; 35 | }; 36 | 37 | export default date; 38 | -------------------------------------------------------------------------------- /docs/assets/js/21.2dfef136.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[21],{447:function(e,t,n){},491:function(e,t,n){"use strict";n(447)},529:function(e,t,n){"use strict";n.r(t);var a={name:"search-demo",props:["trigger"],data:function(){return{columns:[{label:"Name",field:"name",filterOptions:{enabled:!1}},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},r=(n(491),n(4)),o=Object(r.a)(a,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{"search-options":{enabled:!0,trigger:this.trigger},columns:this.columns,rows:this.rows}})],1)}),[],!1,null,null,null);t.default=o.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/22.ec06531f.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[22],{448:function(e,t,a){},492:function(e,t,a){"use strict";a(448)},530:function(e,t,a){"use strict";a.r(t);var n={name:"theme-table",props:["theme","styleClasses"],data:function(){return{columns:[{label:"Name",field:"name",filterOptions:{enabled:!0}},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},s=(a(492),a(4)),l=Object(s.a)(n,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,styleClass:this.styleClasses,theme:this.theme}})],1)}),[],!1,null,null,null);t.default=l.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/38.fc6dd42f.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[38],{549:function(s,t,e){"use strict";e.r(t);var a=e(4),n=Object(a.a)({},(function(){var s=this,t=s.$createElement,e=s._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":s.$parent.slotKey}},[e("h1",{attrs:{id:"sass"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#sass"}},[s._v("#")]),s._v(" Sass")]),s._v(" "),e("p",[s._v("Vue-Good-Table's styling is written in Sass. The source files are made available as part of the npm dependency.")]),s._v(" "),e("p",[e("strong",[s._v("Vue-Good-Table's root Sass file:")])]),s._v(" "),e("div",{staticClass:"language-scss extra-class"},[e("pre",{pre:!0,attrs:{class:"language-scss"}},[e("code",[e("span",{pre:!0,attrs:{class:"token keyword"}},[s._v("@import")]),s._v(" "),e("span",{pre:!0,attrs:{class:"token string"}},[s._v('"../node_modules/vue-good-table/src/styles/style.scss"')]),e("span",{pre:!0,attrs:{class:"token punctuation"}},[s._v(";")]),s._v("\n")])])])])}),[],!1,null,null,null);t.default=n.exports}}]); -------------------------------------------------------------------------------- /vp-docs/.vuepress/theme/components/UserBitAd.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 29 | 30 | 49 | -------------------------------------------------------------------------------- /docs/assets/js/16.b0065a94.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[16],{441:function(e,n,t){},485:function(e,n,t){"use strict";t(441)},523:function(e,n,t){"use strict";t.r(n);var o={name:"grouped-table",props:["options"],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Diet",field:"diet",type:"text"},{label:"Count",field:"count",type:"number"}],rows:[{mode:"span",label:"Mammal",children:[{name:"Elephant",diet:"herbivore",count:5},{name:"Cat",diet:"carnivore",count:28}]},{mode:"span",label:"Reptiles",children:[{name:"Snake",diet:"carnivore",count:40},{name:"lizard",diet:"insectivore",count:34}]},{mode:"span",label:"Fish",children:[{name:"Shark",diet:"carnivore",count:2},{name:"koi",diet:"omnivore",count:14}]}]}},computed:{},methods:{},mounted:function(){},components:{}},i=(t(485),t(4)),a=Object(i.a)(o,(function(){var e=this.$createElement,n=this._self._c||e;return n("div",[n("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,"group-options":this.options,"search-options":{enabled:!0}}})],1)}),[],!1,null,null,null);n.default=a.exports}}]); -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/16.9e087e7c.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[16],{177:function(e,t,a){},183:function(e,t,a){"use strict";var n=a(177);a.n(n).a},204:function(e,t,a){"use strict";a.r(t);var n={name:"theme-table",props:["theme","styleClasses"],data:function(){return{columns:[{label:"Name",field:"name",filterOptions:{enabled:!0}},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"YYYY-MM-DD",dateOutputFormat:"MMM Do YY"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"201-10-31:9: 35 am",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},s=(a(183),a(0)),l=Object(s.a)(n,function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,styleClass:this.styleClasses,theme:this.theme}})],1)},[],!1,null,null,null);t.default=l.exports}}]); -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/17.0ee802cb.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[17],{178:function(e,n,t){},184:function(e,n,t){"use strict";var o=t(178);t.n(o).a},205:function(e,n,t){"use strict";t.r(n);var o={name:"grouped-table",props:["options"],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Diet",field:"diet",type:"text"},{label:"Count",field:"count",type:"number"}],rows:[{mode:"span",label:"Mammal",children:[{name:"Elephant",diet:"herbivore",count:5},{name:"Cat",diet:"carnivore",count:28}]},{mode:"span",label:"Reptiles",children:[{name:"Snake",diet:"carnivore",count:40},{name:"lizard",diet:"insectivore",count:34}]},{mode:"span",label:"Fish",children:[{name:"Shark",diet:"carnivore",count:2},{name:"koi",diet:"omnivore",count:14}]}]}},computed:{},methods:{},mounted:function(){},components:{}},i=(t(184),t(0)),a=Object(i.a)(o,function(){var e=this.$createElement,n=this._self._c||e;return n("div",[n("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,"group-options":this.options,"search-options":{enabled:!0}}})],1)},[],!1,null,null,null);n.default=a.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/8.f51d7e4e.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[8],{433:function(e,t,a){},477:function(e,t,a){"use strict";a(433)},515:function(e,t,a){"use strict";a.r(t);var n={name:"basic-table",props:[],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343},{id:4,name:"Chris",age:55,createdAt:"2011-10-11",score:.03343},{id:5,name:"Dan",age:40,createdAt:"2011-10-21",score:.03343},{id:6,name:"John",age:20,createdAt:"2011-10-31",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(a(477),a(4)),r=Object(o.a)(n,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows}})],1)}),[],!1,null,null,null);t.default=r.exports}}]); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/assets/js/7.3f6cd7fb.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[7],{434:function(t,e,n){},478:function(t,e,n){"use strict";n(434)},516:function(t,e,n){"use strict";n.r(e);var a={name:"action-slot-table",data:function(){return{columns:[{label:"Name",field:"name",filterOptions:{enabled:!1}},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(n(478),n(4)),s=Object(o.a)(a,(function(){var t=this.$createElement,e=this._self._c||t;return e("div",[e("vue-good-table",{attrs:{columns:this.columns,rows:this.rows}},[e("div",{attrs:{slot:"table-actions"},slot:"table-actions"},[e("button",{staticClass:"button"},[this._v("Button 1")]),this._v(" "),e("button",{staticClass:"button"},[this._v("Button 2")])])])],1)}),[],!1,null,null,null);e.default=s.exports}}]); -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var webpackConfig = require('../../build/webpack.test.conf') 7 | 8 | module.exports = function (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | browsers: ['PhantomJS'], 15 | frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'], 16 | reporters: ['spec', 'coverage'], 17 | files: ['./index.js'], 18 | preprocessors: { 19 | './index.js': ['webpack', 'sourcemap'] 20 | }, 21 | webpack: webpackConfig, 22 | webpackMiddleware: { 23 | noInfo: true 24 | }, 25 | coverageReporter: { 26 | dir: './coverage', 27 | reporters: [ 28 | { type: 'lcov', subdir: '.' }, 29 | { type: 'text-summary' } 30 | ] 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/21.6ce211a6.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[21],{182:function(e,t,a){},188:function(e,t,a){"use strict";var n=a(182);a.n(n).a},208:function(e,t,a){"use strict";a.r(t);var n={name:"basic-table",props:[],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"YYYY-MM-DD",dateOutputFormat:"MMM Do YY"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"201-10-31:9: 35 am",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343},{id:4,name:"Chris",age:55,createdAt:"2011-10-11",score:.03343},{id:5,name:"Dan",age:40,createdAt:"2011-10-21",score:.03343},{id:6,name:"John",age:20,createdAt:"2011-10-31",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},r=(a(188),a(0)),o=Object(r.a)(n,function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows}})],1)},[],!1,null,null,null);t.default=o.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/13.941a2941.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[13],{439:function(e,t,a){},483:function(e,t,a){"use strict";a(439)},521:function(e,t,a){"use strict";a.r(t);var n={name:"fixed-header",props:[],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343},{id:4,name:"Chris",age:55,createdAt:"2011-10-11",score:.03343},{id:5,name:"Dan",age:40,createdAt:"2011-10-21",score:.03343},{id:6,name:"John",age:20,createdAt:"2011-10-31",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},r=(a(483),a(4)),d=Object(r.a)(n,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,"max-height":"200px","fixed-header":!0}})],1)}),[],!1,null,null,null);t.default=d.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/19.d6dddf3d.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[19],{445:function(e,t,a){},489:function(e,t,a){"use strict";a(445)},527:function(e,t,a){"use strict";a.r(t);var n={name:"pagination-table",props:["options"],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343},{id:4,name:"Chris",age:55,createdAt:"2011-10-11",score:.03343},{id:5,name:"Dan",age:40,createdAt:"2011-10-21",score:.03343},{id:6,name:"John",age:20,createdAt:"2011-10-31",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(a(489),a(4)),r=Object(o.a)(n,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,"pagination-options":this.options}})],1)}),[],!1,null,null,null);t.default=r.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/11.c8a5abb4.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[11],{437:function(e,t,n){},481:function(e,t,n){"use strict";n(437)},519:function(e,t,n){"use strict";n.r(t);var o={name:"custom-row",props:[],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},a=(n(481),n(4)),r=Object(a.a)(o,(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("vue-good-table",{attrs:{columns:e.columns,rows:e.rows},scopedSlots:e._u([{key:"table-row",fn:function(t){return["age"==t.column.field?n("span",[n("span",{staticStyle:{"font-weight":"bold",color:"blue"}},[e._v(e._s(t.row.age))])]):n("span",[e._v("\n "+e._s(t.formattedRow[t.column.field])+"\n ")])]}}])})],1)}),[],!1,null,null,null);t.default=r.exports}}]); -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/19.5eb669bb.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[19],{180:function(e,t,n){},186:function(e,t,n){"use strict";var o=n(180);n.n(o).a},207:function(e,t,n){"use strict";n.r(t);var o={name:"checkbox-table",props:[],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"YYYY-MM-DD",dateOutputFormat:"MMM Do YY"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"201-10-31:9: 35 am",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{selectAll:function(e){console.log(e)},toggleSelectRow:function(e){console.log(e)}},mounted:function(){},components:{}},l=(n(186),n(0)),a=Object(l.a)(o,function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,"select-options":{enabled:!0},"search-options":{enabled:!0}},on:{"on-select-all":this.selectAll,"on-row-click":this.toggleSelectRow}})],1)},[],!1,null,null,null);t.default=a.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/14.00a22c84.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[14],{440:function(e,n,t){},484:function(e,n,t){"use strict";t(440)},522:function(e,n,t){"use strict";t.r(n);var o={name:"grouped-custom-span",props:["options"],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Diet",field:"diet",type:"text"},{label:"Count",field:"count",type:"number"}],rows:[{mode:"span",label:"Mammal",children:[{name:"Elephant",diet:"herbivore",count:5},{name:"Cat",diet:"carnivore",count:28}]},{mode:"span",label:"Reptiles",children:[{name:"Snake",diet:"carnivore",count:40},{name:"lizard",diet:"insectivore",count:34}]},{mode:"span",label:"Fish",children:[{name:"Shark",diet:"carnivore",count:2},{name:"koi",diet:"omnivore",count:14}]}]}},computed:{},methods:{},mounted:function(){},components:{}},a=(t(484),t(4)),i=Object(a.a)(o,(function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",[t("vue-good-table",{attrs:{columns:e.columns,rows:e.rows,"group-options":e.options,"search-options":{enabled:!0}},scopedSlots:e._u([{key:"table-header-row",fn:function(n){return[t("span",{staticClass:"my-fancy-class"},[e._v("\n "+e._s(n.row.label)+"\n ")])]}}])})],1)}),[],!1,null,null,null);n.default=i.exports}}]); -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/18.57facccb.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[18],{179:function(e,t,n){},185:function(e,t,n){"use strict";var a=n(179);n.n(a).a},206:function(e,t,n){"use strict";n.r(t);var a={name:"custom-row",props:[],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"YYYY-MM-DD",dateOutputFormat:"MMM Do YY"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"201-10-31:9: 35 am",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(n(185),n(0)),r=Object(o.a)(a,function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("vue-good-table",{attrs:{columns:e.columns,rows:e.rows},scopedSlots:e._u([{key:"table-row",fn:function(t){return["age"==t.column.field?n("span",[n("span",{staticStyle:{"font-weight":"bold",color:"blue"}},[e._v(e._s(t.row.age))])]):n("span",[e._v("\n "+e._s(t.formattedRow[t.column.field])+"\n ")])]}}])})],1)},[],!1,null,null,null);t.default=r.exports}}]); -------------------------------------------------------------------------------- /test/unit/specs/types/number.spec.js: -------------------------------------------------------------------------------- 1 | import numberType from '@/components/types/number' 2 | 3 | describe('number type', () => { 4 | describe('compare', () => { 5 | it('should return 1 if x > y for integers', () => { 6 | expect(numberType.compare('2', '1')).to.equal(1) 7 | }) 8 | 9 | it('should return 1 if x > y for float', () => { 10 | expect(numberType.compare('1.2', '1.1')).to.equal(1) 11 | }) 12 | 13 | it('should return 1 if x > y for float', () => { 14 | expect(numberType.compare('1.2', '1.1')).to.equal(1) 15 | }) 16 | 17 | it('should return 1 if x > y for float', () => { 18 | expect(numberType.compare(1.2, 1.1)).to.equal(1) 19 | }) 20 | }) 21 | describe('filterPredicate', () => { 22 | it('should return true only in case of exact equality', () => { 23 | expect(numberType.filterPredicate('1.2', '1.2')).to.equal(true) 24 | }) 25 | 26 | it('should return true only in case of numeric equality', () => { 27 | expect(numberType.filterPredicate('1.2', '1.20')).to.equal(true) 28 | }) 29 | 30 | it('should return false else', () => { 31 | expect(numberType.filterPredicate('1.2', '12')).to.equal(false) 32 | }) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/other-projects.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 39 | 40 | 48 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | var server = require('../../build/dev-server.js') 4 | 5 | server.ready.then(() => { 6 | // 2. run the nightwatch test suite against it 7 | // to run in additional browsers: 8 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 9 | // 2. add it to the --env flag below 10 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 11 | // For more information on Nightwatch's config file, see 12 | // http://nightwatchjs.org/guide#settings-file 13 | var opts = process.argv.slice(2) 14 | if (opts.indexOf('--config') === -1) { 15 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 16 | } 17 | if (opts.indexOf('--env') === -1) { 18 | opts = opts.concat(['--env', 'chrome']) 19 | } 20 | 21 | var spawn = require('cross-spawn') 22 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 23 | 24 | runner.on('exit', function (code) { 25 | server.close() 26 | process.exit(code) 27 | }) 28 | 29 | runner.on('error', function (err) { 30 | server.close() 31 | throw err 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /docs/assets/js/18.23bc9f91.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[18],{443:function(t,e,s){},487:function(t,e,s){"use strict";s(443)},525:function(t,e,s){"use strict";s.r(e);var a={name:"other-projects",props:[],data:function(){return{}},computed:{},methods:{},mounted:function(){},components:{}},i=(s(487),s(4)),o=Object(i.a)(a,(function(){var t=this.$createElement;this._self._c;return this._m(0)}),[function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",[s("h4",[t._v("You might also like")]),t._v(" "),s("div",{staticClass:"features"},[s("div",{staticClass:"feature"},[s("h2",[s("a",{attrs:{href:"https://github.com/xaksis/vue-good-wizard"}},[t._v("vue-good-wizard")])]),t._v(" "),s("p",[t._v("An easy to use and clean VueJS step wizard plugin.")])]),t._v(" "),s("div",{staticClass:"feature"},[s("h2",[s("a",{attrs:{href:"https://github.com/xaksis/vue-good-links"}},[t._v("vue-good-links")])]),t._v(" "),s("p",[t._v("A light, expandable link and text hover effect library for VueJS.")])]),t._v(" "),s("div",{staticClass:"feature"},[s("h2",[s("a",{attrs:{href:"https://userbitapp.com"}},[t._v("UserBit")])]),t._v(" "),s("p",[t._v("Cloud-based platform for UX and Product teams.")])])])])}],!1,null,"e0df4b64",null);e.default=o.exports}}]); -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/gettingstarted#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: require('selenium-server').path, 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/components/types/default.js: -------------------------------------------------------------------------------- 1 | import { diacriticless } from '../utils/diacritics'; 2 | 3 | const escapeRegExp = str => str.replace(/[\\^$*+?.()|[\]{}]/g, '\\$&'); 4 | 5 | export default { 6 | format(x) { 7 | return x; 8 | }, 9 | filterPredicate(rowval, filter, skipDiacritics = false, fromDropdown = false) { 10 | // take care of nulls 11 | if (typeof rowval === 'undefined' || rowval === null) { 12 | return false; 13 | } 14 | 15 | // row value 16 | const rowValue = skipDiacritics 17 | ? String(rowval).toLowerCase() 18 | : diacriticless(escapeRegExp(String(rowval)).toLowerCase()); 19 | 20 | // search term 21 | const searchTerm = skipDiacritics 22 | ? filter.toLowerCase() 23 | : diacriticless(escapeRegExp(filter).toLowerCase()); 24 | 25 | // comparison 26 | return fromDropdown ? rowValue === searchTerm : (rowValue.indexOf(searchTerm) > -1); 27 | }, 28 | 29 | compare(x, y) { 30 | function cook(d) { 31 | if (typeof d === 'undefined' || d === null) return ''; 32 | return diacriticless(String(d).toLowerCase()); 33 | } 34 | x = cook(x); 35 | y = cook(y); 36 | if (x < y) return -1; 37 | if (x > y) return 1; 38 | return 0; 39 | }, 40 | }; 41 | -------------------------------------------------------------------------------- /test/unit/specs/types/date.spec.js: -------------------------------------------------------------------------------- 1 | import dateType from '@/components/types/date' 2 | 3 | describe('date type', () => { 4 | describe('compare', () => { 5 | it('should compare dates correctly', () => { 6 | expect(dateType.compare('20001211', '20001112')).to.equal(1) 7 | }) 8 | 9 | it('should compare dates correctly with custom format', () => { 10 | expect(dateType.compare('20001211', '20001112', {inputFormat: 'YYYYDDMM'})).to.equal(-1) 11 | }) 12 | 13 | it('should compare null date as epoch', () => { 14 | expect(dateType.compare('20001211', undefined, {inputFormat: 'YYYYDDMM'})).to.equal(1) 15 | }) 16 | 17 | it('should compare null date as epoch', () => { 18 | expect(dateType.compare(undefined, '20001211', {inputFormat: 'YYYYDDMM'})).to.equal(-1) 19 | }) 20 | }) 21 | 22 | describe('format', () => { 23 | it('should format dates correctly', () => { 24 | expect(dateType.format('20001012', {inputFormat: 'YYYYDDMM', outputFormat: 'Do MMM YYYY'})).to.equal('10th Dec 2000') 25 | }) 26 | 27 | it('should format dates correctly', () => { 28 | expect(dateType.format('20001012', {inputFormat: 'YYYYMMDD', outputFormat: 'Do MMM YYYY'})).to.equal('12th Oct 2000') 29 | }) 30 | }) 31 | }) 32 | -------------------------------------------------------------------------------- /docs/assets/js/10.54b5e228.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[10],{436:function(e,t,o){},480:function(e,t,o){"use strict";o(436)},518:function(e,t,o){"use strict";o.r(t);var n={name:"checkbox-table",props:["showSlot"],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{selectAll:function(e){console.log(e)},toggleSelectRow:function(e){console.log(e)}},mounted:function(){},components:{}},s=(o(480),o(4)),l=Object(s.a)(n,(function(){var e=this.$createElement,t=this._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:this.columns,rows:this.rows,"select-options":{enabled:!0},"search-options":{enabled:!0}},on:{"on-selected-rows-change":this.toggleSelectRow}},[this.showSlot?t("div",{attrs:{slot:"selected-row-actions"},slot:"selected-row-actions"},[t("button",[this._v("Action 1")])]):this._e()])],1)}),[],!1,null,null,null);t.default=l.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/9.e00df4e4.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[9],{435:function(e,t,n){},479:function(e,t,n){"use strict";n(435)},517:function(e,t,n){"use strict";n.r(t);var a={name:"before-after-columns",props:[],data:function(){return{columns:[{label:"Before",field:"before"},{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"},{label:"After",field:"after"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(n(479),n(4)),r=Object(o.a)(a,(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[n("vue-good-table",{attrs:{columns:e.columns,rows:e.rows},scopedSlots:e._u([{key:"table-row",fn:function(t){return["before"==t.column.field?n("span",[e._v("\n before\n ")]):"after"==t.column.field?n("span",[e._v("\n after\n ")]):n("span",[e._v("\n "+e._s(t.formattedRow[t.column.field])+"\n ")])]}}])})],1)}),[],!1,null,null,null);t.default=r.exports}}]); -------------------------------------------------------------------------------- /docs/assets/js/12.36cf977b.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[12],{438:function(e,t,n){},482:function(e,t,n){"use strict";n(438)},520:function(e,t,n){"use strict";n.r(t);var a={name:"external-query",props:[],data:function(){return{externalQuery:"",columns:[{label:"Name",field:"name",filterOptions:{enabled:!1}},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"yyyy-MM-dd",dateOutputFormat:"MMM do yy"},{label:"Percent",field:"score",type:"percentage"}],rows:[{id:1,name:"John",age:20,createdAt:"2011-07-02",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},r=(n(482),n(4)),o=Object(r.a)(a,(function(){var e=this,t=e.$createElement,n=e._self._c||t;return n("div",[e._v("\n External Query "),n("input",{directives:[{name:"model",rawName:"v-model",value:e.externalQuery,expression:"externalQuery"}],attrs:{type:"text"},domProps:{value:e.externalQuery},on:{input:function(t){t.target.composing||(e.externalQuery=t.target.value)}}}),e._v(" "),n("vue-good-table",{attrs:{"search-options":{enabled:!0,externalQuery:e.externalQuery},columns:e.columns,rows:e.rows}})],1)}),[],!1,null,null,null);t.default=o.exports}}]); -------------------------------------------------------------------------------- /test/unit/specs/types/default.spec.js: -------------------------------------------------------------------------------- 1 | import defaultType from '@/components/types/default' 2 | 3 | describe('default type', () => { 4 | describe('compare', () => { 5 | it('should return -1 if x is before y', () => { 6 | expect(defaultType.compare('abc', 'abd')).to.equal(-1) 7 | }) 8 | 9 | it('should return 1 if y is before x', () => { 10 | expect(defaultType.compare('aba', 'aaa')).to.equal(1) 11 | }) 12 | 13 | it('should return 0 if y == x', () => { 14 | expect(defaultType.compare('aba', 'aba')).to.equal(0) 15 | }) 16 | }) 17 | describe('format', () => { 18 | it('should return itself', () => { 19 | var x = '
lorem ipsum
' 20 | expect(defaultType.format(x)).to.equal(x) 21 | }) 22 | }) 23 | describe('filterPredicate', () => { 24 | it('should return false if values don\'t match', () => { 25 | expect(defaultType.filterPredicate('aBc', 'aBcD')).to.equal(false) 26 | }) 27 | 28 | it('should return true if values match', () => { 29 | expect(defaultType.filterPredicate('aBc', 'aBc')).to.equal(true) 30 | }) 31 | 32 | it('should return true if values match, even if they are mismatch on case', () => { 33 | expect(defaultType.filterPredicate('aBc', 'AbC')).to.equal(true) 34 | }) 35 | }) 36 | }) 37 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/20.6c61e0f6.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[20],{181:function(e,n,t){},187:function(e,n,t){"use strict";var a=t(181);t.n(a).a},209:function(e,n,t){"use strict";t.r(n);var a={name:"before-after-columns",props:[],data:function(){return{columns:[{label:"Before",field:"before"},{label:"Name",field:"name"},{label:"Age",field:"age",type:"number"},{label:"Created On",field:"createdAt",type:"date",dateInputFormat:"YYYY-MM-DD",dateOutputFormat:"MMM Do YY"},{label:"Percent",field:"score",type:"percentage"},{label:"After",field:"after"}],rows:[{id:1,name:"John",age:20,createdAt:"201-10-31:9: 35 am",score:.03343},{id:2,name:"Jane",age:24,createdAt:"2011-10-31",score:.03343},{id:3,name:"Susan",age:16,createdAt:"2011-10-30",score:.03343}]}},computed:{},methods:{},mounted:function(){},components:{}},o=(t(187),t(0)),r=Object(o.a)(a,function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",[t("vue-good-table",{attrs:{columns:e.columns,rows:e.rows},scopedSlots:e._u([{key:"table-row",fn:function(n){return["before"==n.column.field?t("span",[e._v("\n before\n ")]):"after"==n.column.field?t("span",[e._v("\n after\n ")]):t("span",[e._v("\n "+e._s(n.formattedRow[n.column.field])+"\n ")])]}}])})],1)},[],!1,null,null,null);n.default=r.exports}}]); -------------------------------------------------------------------------------- /vp-docs/guide/style-configuration/style-classes.md: -------------------------------------------------------------------------------- 1 | # Style Classes 2 | 3 | Vue-good-table allows providing your own css classes for the table via **styleClass** option but it also has in-built classes that you can make use of. 4 | 5 | ::: tip NOTE 6 | by default, tables have 'vgt-table striped bordered' 7 | ::: 8 | 9 | ## .vgt-table 10 | Base class that initializes all the core styles for the table. 11 | ```vue{4} 12 | 16 | 17 | ``` 18 | 19 | 20 | ## .vgt-table .striped 21 | Add row striping in your data table. 22 | ```vue{4} 23 | 27 | 28 | ``` 29 | 30 | 31 | ## .vgt-table .bordered 32 | Add borders to columns/rows 33 | ```vue{4} 34 | 38 | 39 | ``` 40 | 41 | 42 | ## .vgt-table .condensed 43 | Have lots of rows? use condensed class to get more compact rows. 44 | ```vue{4} 45 | 49 | 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/assets/js/15.2193695d.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[15],{442:function(n,e,t){},486:function(n,e,t){"use strict";t(442)},524:function(n,e,t){"use strict";t.r(e);var o={name:"grouped-custom",props:["options"],data:function(){return{columns:[{label:"Name",field:"name"},{label:"Diet",field:"diet",type:"text"},{label:"Count",field:"count",type:"number"},{label:"Action",field:"action",type:"number"}],rows:[{name:"Mammal",diet:"",count:"",children:[{name:"Elephant",diet:"herbivore",count:5},{name:"Cat",diet:"carnivore",count:28}]},{name:"Reptiles",diet:"",count:"",action:"",children:[{name:"Snake",diet:"carnivore",count:40},{name:"lizard",diet:"insectivore",count:34}]},{name:"Fish",diet:"",count:"",children:[{name:"Shark",diet:"carnivore",count:2},{name:"koi",diet:"omnivore",count:14}]}]}},computed:{},methods:{showAlert:function(n){alert(JSON.stringify(n))}},mounted:function(){},components:{}},i=(t(486),t(4)),c=Object(i.a)(o,(function(){var n=this,e=n.$createElement,t=n._self._c||e;return t("div",[t("vue-good-table",{attrs:{columns:n.columns,rows:n.rows,"group-options":n.options,"search-options":{enabled:!0}},scopedSlots:n._u([{key:"table-header-row",fn:function(e){return["action"==e.column.field?t("span",[t("button",{staticClass:"fancy-btn",on:{click:function(t){return n.showAlert(e)}}},[n._v("Action")])]):t("span",[n._v("\n "+n._s(e.formattedRow[e.column.field])+"\n ")])]}}])})],1)}),[],!1,null,null,null);e.default=c.exports}}]); -------------------------------------------------------------------------------- /vp-docs/.vuepress/theme/components/CarbonAds.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 42 | 43 | 78 | -------------------------------------------------------------------------------- /docs/assets/js/6.9355beb5.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[6],{451:function(e,t,o){},495:function(e,t,o){"use strict";o(451)},532:function(e,t,o){"use strict";o.r(t);o(27),o(63),o(89),o(64);var a={name:"CodeGroup",data:function(){return{codeTabs:[],activeCodeTabIndex:-1}},watch:{activeCodeTabIndex:function(e){this.codeTabs.forEach((function(e){e.elm.classList.remove("theme-code-block__active")})),this.codeTabs[e].elm.classList.add("theme-code-block__active")}},mounted:function(){var e=this;this.codeTabs=(this.$slots.default||[]).filter((function(e){return Boolean(e.componentOptions)})).map((function(t,o){return""===t.componentOptions.propsData.active&&(e.activeCodeTabIndex=o),{title:t.componentOptions.propsData.title,elm:t.elm}})),-1===this.activeCodeTabIndex&&this.codeTabs.length>0&&(this.activeCodeTabIndex=0)},methods:{changeCodeTab:function(e){this.activeCodeTabIndex=e}}},c=(o(495),o(4)),n=Object(c.a)(a,(function(){var e=this,t=e.$createElement,o=e._self._c||t;return o("div",{staticClass:"theme-code-group"},[o("div",{staticClass:"theme-code-group__nav"},[o("ul",{staticClass:"theme-code-group__ul"},e._l(e.codeTabs,(function(t,a){return o("li",{key:t.title,staticClass:"theme-code-group__li"},[o("button",{staticClass:"theme-code-group__nav-tab",class:{"theme-code-group__nav-tab-active":a===e.activeCodeTabIndex},on:{click:function(t){return e.changeCodeTab(a)}}},[e._v("\n "+e._s(t.title)+"\n ")])])})),0)]),e._v(" "),e._t("default"),e._v(" "),e.codeTabs.length<1?o("pre",{staticClass:"pre-blank"},[e._v("// Make sure to add code blocks to your code group")]):e._e()],2)}),[],!1,null,"32c2d7ed",null);t.default=n.exports}}]); -------------------------------------------------------------------------------- /vp-docs/guide/configuration/sort-options.md: -------------------------------------------------------------------------------- 1 | # Sort Options 2 | 3 | Set of options related to table sorting 4 | 5 | ```html 6 | 13 | 14 | ``` 15 | 16 | ## enabled 17 | 18 | type: `Boolean (default: true)` 19 | 20 | Enable/disable sorting on table as a whole. 21 | ```html 22 | 28 | 29 | ``` 30 | 31 | ## initialSortBy 32 | 33 | ::: tip Update 34 | `initialSortBy` now allows for sort by multiple columns 35 | ::: 36 | 37 | type: `Object` or `Array` 38 | 39 | Allows specifying a default sort for the table on wakeup. Both **field** and **type** values are required. 40 | ```html 41 | 48 | 49 | ``` 50 | 51 | ## multipleColumns 52 | 53 | type: `Boolean (default: true)` 54 | 55 | Enable/disable multiple column sort. Users can shift-click on multiple columns to sort by multiple columns. The first column in the array gets primary sort. 56 | 57 | ```html 58 | 69 | 70 | ``` -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/basic-table.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 59 | 60 | 66 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/rtl-table.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 59 | 60 | 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-good-table", 3 | "version": "2.21.11", 4 | "sideEffects": [ 5 | "*.vue", 6 | "*.css" 7 | ], 8 | "description": "A simple, clean data table for VueJS (2.x) with essential features like sorting, column filtering, pagination etc", 9 | "main": "dist/vue-good-table.cjs.js", 10 | "module": "dist/vue-good-table.esm.js", 11 | "files": [ 12 | "dist", 13 | "src" 14 | ], 15 | "scripts": { 16 | "bundle": "bili", 17 | "dev": "poi --serve", 18 | "docs:dev": "vuepress dev vp-docs", 19 | "docs:build": "vuepress build vp-docs", 20 | "test": "echo \"No test specified\"" 21 | }, 22 | "repository": "github:xaksis/vue-good-table", 23 | "keywords": [ 24 | "vue", 25 | "vuejs", 26 | "table", 27 | "datatable" 28 | ], 29 | "author": { 30 | "name": "xaksis", 31 | "email": "shay@crayonbits.com" 32 | }, 33 | "license": "MIT", 34 | "poi": { 35 | "entry": "dev/main.js", 36 | "output": { 37 | "dir": "dev/dist", 38 | "publicUrl": "./", 39 | "html": { 40 | "template": "dev/index.html" 41 | } 42 | } 43 | }, 44 | "dependencies": { 45 | "date-fns": "^2.17.0", 46 | "lodash.isequal": "^4.5.0" 47 | }, 48 | "devDependencies": { 49 | "@vuepress/plugin-google-analytics": "^1.0.0-rc.1", 50 | "bili": "^4.8.0", 51 | "eslint-config-airbnb": "^18.2.0", 52 | "node-sass": "^4.12.0", 53 | "poi": "^12.7.0", 54 | "rollup-plugin-commonjs": "^10.1.0", 55 | "rollup-plugin-vue": "^5.1.9", 56 | "sass-loader": "^7.1.0", 57 | "vue": "^2.6.10", 58 | "vue-template-compiler": "^2.6.10", 59 | "vuepress": "^1.0.0-rc.1" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/unit/specs/Pagination.spec.js: -------------------------------------------------------------------------------- 1 | import sinon from 'sinon' 2 | import VueGoodPagination from '@/components/Pagination' 3 | import { mount } from 'vue-test-utils' 4 | 5 | describe('VueGoodPagination', () => { 6 | let wrapper, vm 7 | beforeEach(() => { 8 | wrapper = mount(VueGoodPagination, {propsData: { 9 | perPage: 10, 10 | total: 30} 11 | }) 12 | vm = wrapper.vm 13 | }) 14 | it('should render 2 page buttons', async () => { 15 | await vm.$nextTick() 16 | wrapper.findAll('.page-btn').length.should.equal(2) 17 | wrapper.contains('select').should.be.true 18 | }) 19 | 20 | it('should call previousPage when the first button is clicked', async () => { 21 | await vm.$nextTick() 22 | let previousPageStub = sinon.stub(vm, 'previousPage') 23 | wrapper.find('.page-btn:first-child').trigger('click') 24 | previousPageStub.called.should.be.true 25 | }) 26 | 27 | it('should call nextPage when the last button is clicked', async () => { 28 | await vm.$nextTick() 29 | let nextPageStub = sinon.stub(vm, 'nextPage') 30 | wrapper.find('.page-btn:last-child').trigger('click') 31 | nextPageStub.called.should.be.true 32 | }) 33 | 34 | it('should call pageChanged during nextPage', async () => { 35 | await vm.$nextTick() 36 | let pageChangedStub = sinon.stub(vm, 'pageChanged') 37 | vm.nextPage() 38 | pageChangedStub.called.should.be.true 39 | }) 40 | 41 | it('should call pageChanged during previousPage', async () => { 42 | await vm.$nextTick() 43 | vm.nextPage() 44 | let pageChangedStub = sinon.stub(vm, 'pageChanged') 45 | vm.previousPage() 46 | pageChangedStub.called.should.be.true 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/line-numbers-table.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 59 | 60 | 76 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/fixed-header.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 61 | 62 | 67 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/custom-row.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 64 | 65 | 70 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/theme-example.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 61 | 62 | 78 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/search-demo.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 65 | 66 | 82 | -------------------------------------------------------------------------------- /src/components/VgtGlobalSearch.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 64 | 65 | 68 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/external-query.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 66 | 67 | 83 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/checkbox-table.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 70 | 71 | 77 | -------------------------------------------------------------------------------- /src/styles/_control-bar.scss: -------------------------------------------------------------------------------- 1 | .vgt-global-search{ 2 | padding: 5px 0px; 3 | display: flex; 4 | flex-wrap: nowrap; 5 | align-items: stretch; 6 | border: 1px solid $border-color; 7 | border-bottom: 0px; 8 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 9 | form { 10 | display: flex; 11 | label { 12 | margin-top: 3px; 13 | } 14 | } 15 | } 16 | .vgt-global-search__input{ 17 | position: relative; 18 | padding-left: 40px; 19 | flex-grow: 1; 20 | .input__icon{ 21 | position: absolute; 22 | left: 0px; 23 | max-width: 32px; 24 | .magnifying-glass{ 25 | margin-top: 3px; 26 | margin-left: 8px; 27 | display: block; 28 | width: 16px; 29 | height: 16px; 30 | border: 2px solid #494949; 31 | position: relative; 32 | border-radius: 50%; 33 | &:before{ 34 | content: ""; 35 | display: block; 36 | position: absolute; 37 | right: -7px; 38 | bottom: -5px; 39 | background: #494949; 40 | width: 8px; 41 | height: 4px; 42 | border-radius: 2px; 43 | transform: rotate(45deg); 44 | -webkit-transform: rotate(45deg); 45 | -moz-transform: rotate(45deg); 46 | -ms-transform: rotate(45deg); 47 | -o-transform: rotate(45deg); 48 | } 49 | } 50 | } 51 | .vgt-input{ 52 | } 53 | } 54 | .vgt-global-search__actions{ 55 | margin-left: 10px; 56 | } 57 | 58 | .vgt-selection-info-row{ 59 | background: $notify-bg-color; 60 | padding: 5px 16px; 61 | font-size: 13px; 62 | border-top: 1px solid $border-color; 63 | border-left: 1px solid $border-color; 64 | border-right: 1px solid $border-color; 65 | color: lighten($notify-fg-color, 10%); 66 | font-weight: bold; 67 | a{ 68 | font-weight: bold; 69 | display: inline-block; 70 | margin-left: 10px; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/pagination-table.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 60 | 61 | 77 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | title: 'vue-good-table', 3 | description: 'A powerful data table plugin for VueJS', 4 | base: '/vue-good-table/', 5 | dest: 'docs', 6 | ga: 'UA-120929110-1', 7 | head: [ 8 | ['link', { rel: 'icon', href: '/favicon.png' }] 9 | ], 10 | theme: '@vuepress/vue', 11 | themeConfig: { 12 | repo: 'xaksis/vue-good-table', 13 | logo: '/vgt-logo.png', 14 | lastUpdated: true, 15 | nav: [ 16 | { text: 'Home', link: '/' }, 17 | { text: 'Guide', link: '/guide/' }, 18 | ], 19 | sidebar: { 20 | '/guide/': [ 21 | { 22 | title: 'Introduction', 23 | collapsable: false, 24 | children: [ 25 | '', 26 | ] 27 | }, 28 | { 29 | title: 'Configuration', 30 | collapsable: false, 31 | children: [ 32 | '/guide/configuration/', 33 | '/guide/configuration/table-events', 34 | '/guide/configuration/search-options', 35 | '/guide/configuration/sort-options', 36 | '/guide/configuration/pagination-options', 37 | '/guide/configuration/column-options', 38 | '/guide/configuration/column-filter-options', 39 | ] 40 | }, 41 | { 42 | title: 'Advanced Configuration', 43 | collapsable: false, 44 | children: [ 45 | '/guide/advanced/', 46 | '/guide/advanced/checkbox-table', 47 | '/guide/advanced/grouped-table', 48 | '/guide/advanced/remote-workflow', 49 | ] 50 | }, 51 | { 52 | title: 'Style Configuration', 53 | collapsable: false, 54 | children: [ 55 | '/guide/style-configuration/', 56 | '/guide/style-configuration/style-classes', 57 | '/guide/style-configuration/sass', 58 | ] 59 | }, 60 | ], 61 | }, 62 | } 63 | } -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/before-after-columns.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 75 | 76 | 82 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/grouped-table.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 74 | 75 | 91 | -------------------------------------------------------------------------------- /src/components/utils/sort.js: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_SORT_TYPE, 3 | SORT_TYPES, 4 | } from './constants'; 5 | 6 | function getColumnFirstSortType(column) { 7 | return column.firstSortType || DEFAULT_SORT_TYPE; 8 | } 9 | 10 | function getCurrentPrimarySort(sortArray, column) { 11 | return ( sortArray.length === 1 && sortArray[0].field === column.field ) 12 | ? sortArray[0].type 13 | : undefined; 14 | } 15 | 16 | function getNextSort(currentSort, column) { 17 | if (SORT_TYPES.Descending === getColumnFirstSortType(column) 18 | && currentSort === SORT_TYPES.Ascending) { 19 | return SORT_TYPES.None 20 | } else if (currentSort === SORT_TYPES.Ascending) { 21 | return SORT_TYPES.Descending; 22 | } 23 | if (SORT_TYPES.Descending === getColumnFirstSortType(column) 24 | && currentSort === SORT_TYPES.Descending) { 25 | return SORT_TYPES.Ascending; 26 | } else if (currentSort === SORT_TYPES.Descending) { 27 | return SORT_TYPES.None; 28 | } 29 | 30 | if (SORT_TYPES.Descending === getColumnFirstSortType(column) 31 | && currentSort === SORT_TYPES.None) { 32 | return SORT_TYPES.Descending; 33 | } else { 34 | return SORT_TYPES.Ascending; 35 | } 36 | 37 | } 38 | 39 | function getIndex(sortArray, column) { 40 | for (let i = 0; i < sortArray.length; i++) { 41 | if (column.field === sortArray[i].field) return i; 42 | } 43 | return -1; 44 | } 45 | 46 | const primarySort = (sortArray, column) => { 47 | const currentPrimarySort = getCurrentPrimarySort(sortArray, column); 48 | const nextPrimarySort = getNextSort(currentPrimarySort, column); 49 | return [{ 50 | field: column.field, 51 | type: currentPrimarySort ? nextPrimarySort : getColumnFirstSortType(column), 52 | }]; 53 | }; 54 | 55 | const secondarySort = (sortArray, column) => { 56 | const index = getIndex(sortArray, column); 57 | if (index === -1) { 58 | sortArray.push({ 59 | field: column.field, 60 | type: getColumnFirstSortType(column), 61 | }); 62 | } else { 63 | sortArray[index].type = getNextSort(sortArray[index].type, column); 64 | } 65 | return sortArray; 66 | }; 67 | 68 | export { 69 | primarySort, 70 | secondarySort, 71 | } -------------------------------------------------------------------------------- /vp-docs/.vuepress/theme/components/Banner.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 26 | 27 | -------------------------------------------------------------------------------- /vp-docs/guide/advanced/checkbox-table.md: -------------------------------------------------------------------------------- 1 | # Checkbox Table 2 | 3 | One of the most common customizations in datatables is selectable rows. Creating a checkbox table with **vue-good-table** is easier than ever. 4 | 5 | 6 | ## Configuration 7 | 8 | type: `Object` 9 | 10 | Object containing select options 11 | ```html 12 | 25 | ``` 26 | 27 | Although, the `on-selected-rows-change` event should be enough for you to keep track of selected rows. If at any time you need to know what rows are selected, you can get it via ref. 28 | 29 | ```js 30 | this.$refs['my-table'].selectedRows; 31 | ``` 32 | 33 | ### Example 34 | ```vue 35 | 41 | 42 | ``` 43 | 44 | 45 | 46 | 47 | ## Selected row action slot 48 | Once you select a row, an info bar shows up. This bar allows for a customizable slot for your action buttons. 49 | 50 | ### Example 51 | 52 | ```html 53 | 61 |
62 | 63 |
64 |
65 | 66 | ``` 67 | 68 | 69 | 70 | ::: tip Note 71 | You can style the selection info bar by supplying a css class to `selectionInfoClass` property. 72 | ::: -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/action-slot-table.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 62 | 63 | 96 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-good-table 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

404

How did we get here?
Take me home.
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /vp-docs/guide/configuration/column-filter-options.md: -------------------------------------------------------------------------------- 1 | # Column Filter Options 2 | 3 | ## filterOptions 4 | 5 | type `Object` 6 | 7 | A collection of filter specific properties within a column object. 8 | 9 | ```javascript 10 | columns: [ 11 | { 12 | label: 'name', 13 | field: 'user_name', 14 | filterOptions: { 15 | styleClass: 'class1', // class to be added to the parent th element 16 | enabled: true, // enable filter for this column 17 | placeholder: 'Filter This Thing', // placeholder for filter input 18 | filterValue: 'Jane', // initial populated value for this filter 19 | filterDropdownItems: [], // dropdown (with selected values) instead of text input 20 | filterFn: this.columnFilterFn, //custom filter function that 21 | trigger: 'enter', //only trigger on enter not on keyup 22 | }, 23 | }, 24 | // ... 25 | ] 26 | ``` 27 | 28 | ## styleClass 29 | 30 | type: `string` 31 | Class to be added to the parent th element. You can specify several classes separated by a space. 32 | 33 | ## enabled 34 | 35 | type: `Boolean` 36 | Switch to enable column filter. 37 | 38 | ## placeholder 39 | 40 | type: `String` 41 | Placeholder to use on the column filter input. 42 | 43 | ## filterValue 44 | 45 | type: `String` 46 | If you want filter to be pre-populated, use this property 47 | 48 | ## trigger 49 | 50 | type: `String (default: '')` 51 | Allows specifying trigger for column filter. Default trigger is keyup. use 'enter' to filter only when enter key is pressed. 52 | 53 | ## filterDropdownItems 54 | 55 | type `Array of strings or Array of objects` 56 | 57 | allows creating a dropdown for filter as opposed to an input 58 | 59 | ```javascript 60 | //array 61 | filterDropdownItems: ['Blue', 'Red', 'Yellow'] 62 | //or 63 | filterDropdownItems: [ 64 | { value: 'n', text: 'Inactive' }, 65 | { value: 'y', text: 'Active' }, 66 | { value: 'c', text: 'Check' } 67 | ], 68 | ``` 69 | 70 | ## filterFn 71 | 72 | type `Function` 73 | 74 | Custom filter, function of two variables: function(data, filterString), should return true if data matches the filterString, otherwise false 75 | 76 | ```javascript 77 | filterFn: function(data, filterString) { 78 | var x = parseInt(filterString) 79 | return data >= x - 5 && data <= x + 5; 80 | } 81 | // would create a filter matching numbers within 5 of the provided value 82 | ``` 83 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/grouped-custom-span.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 79 | 80 | 100 | -------------------------------------------------------------------------------- /docs/assets/js/3.e88f9927.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[3],{429:function(t,e,n){},430:function(t,e,n){},431:function(t,e,n){},473:function(t,e,n){"use strict";n(429)},474:function(t,e,n){"use strict";n(430)},475:function(t,e,n){"use strict";n(431)},513:function(t,e,n){"use strict";n.r(e);var s=n(496),a={name:"CarbonAds",props:[],data:function(){return{}},watch:{$route:function(t,e){t.path!==e.path&&this.$el.querySelector("#carbonads")&&(this.$el.innerHTML="",this.load())}},computed:{},methods:{load:function(){var t=document.createElement("script");t.id="_carbonads_js",t.src="//cdn.carbonads.com/carbon.js?serve=CK7DC53W&placement=xaksisgithubio",this.$el.appendChild(t)}},mounted:function(){this.load()},components:{}},o=(n(473),n(4)),r=Object(o.a)(a,(function(){var t=this.$createElement;return(this._self._c||t)("div",{staticClass:"carbon-ads"})}),[],!1,null,null,null).exports,i={name:"Banner",props:[],data:function(){return{}},computed:{},methods:{},mounted:function(){},components:{}},c=(n(474),Object(o.a)(i,(function(){var t=this.$createElement;this._self._c;return this._m(0)}),[function(){var t=this.$createElement,e=this._self._c||t;return e("div",{staticClass:"banner-holder"},[e("p",{staticClass:"banner-label"},[this._v("Did "),e("strong",[this._v("vue-good-table")]),this._v(" save you time? Share the Joy!")]),this._v(" "),e("a",{staticClass:"bmc-button",attrs:{target:"_blank",href:"https://www.buymeacoffee.com/68BUXR1d9"}},[e("img",{attrs:{src:"https://www.buymeacoffee.com/assets/img/BMC-btn-logo.svg",alt:"Buy me a coffee"}}),e("span",{staticStyle:{"margin-left":"5px"}},[this._v("Buy me a coffee")])])])}],!1,null,"67e317d2",null).exports),u={name:"UserBitAd",props:[],data:function(){return{}},computed:{},methods:{},mounted:function(){},components:{}},l=(n(475),Object(o.a)(u,(function(){var t=this.$createElement;this._self._c;return this._m(0)}),[function(){var t=this.$createElement,e=this._self._c||t;return e("div",[e("div",{staticClass:"box"},[e("div",{staticClass:"ad-box"},[this._v("\n Do you have a UX team? I Would really appreciate their feedback on my new product - "),e("a",{attrs:{target:"_blank",rel:"noopener noreferrer",href:"https://userbitapp.com"}},[this._v("UserBit")])])])])}],!1,null,"4fb0bc70",null).exports),d={components:{ParentLayout:s.a,CarbonAds:r,Banner:c,UserBitAd:l}},h=Object(o.a)(d,(function(){var t=this.$createElement,e=this._self._c||t;return e("ParentLayout",[e("carbon-ads",{attrs:{slot:"sidebar-top"},slot:"sidebar-top"}),this._v(" "),e("user-bit-ad",{attrs:{slot:"page-top"},slot:"page-top"})],1)}),[],!1,null,null,null);e.default=h.exports}}]); -------------------------------------------------------------------------------- /vp-docs/guide/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Getting Started 3 | 4 | ## Installation 5 | 6 | Install with npm: 7 | 8 | ```bash 9 | npm install --save vue-good-table 10 | ``` 11 | 12 | Import globally in app: 13 | 14 | ```javascript 15 | import VueGoodTablePlugin from 'vue-good-table'; 16 | 17 | // import the styles 18 | import 'vue-good-table/dist/vue-good-table.css' 19 | 20 | Vue.use(VueGoodTablePlugin); 21 | ``` 22 | 23 | **or** you can import into your component: 24 | ```js 25 | // import the styles 26 | import 'vue-good-table/dist/vue-good-table.css' 27 | import { VueGoodTable } from 'vue-good-table'; 28 | 29 | // add to component 30 | components: { 31 | VueGoodTable, 32 | } 33 | ``` 34 | 35 | 36 | ## Basic Example 37 | 38 | 39 | 40 | ```vue 41 | 48 | 49 | 89 | ``` 90 | 91 | ## Usage with Nuxt.js 92 | 93 | Create your own plugin by creating a file called `vue-good-table.js` inside your Nuxt `plugins` folder. Shoud look something like this: 94 | 95 | ``` 96 | import Vue from 'vue' 97 | import VueGoodTablePlugin from 'vue-good-table'; 98 | 99 | // import the styles 100 | import 'vue-good-table/dist/vue-good-table.css' 101 | 102 | Vue.use(VueGoodTablePlugin); 103 | ``` 104 | 105 | As you can see, the only difference from the normal installation is that we need to reference Vue using `import Vue from 'vue'`. 106 | 107 | Next we need to declare the plugin inside your `nuxt.config.js` like so: 108 | 109 | ``` 110 | plugins: [ 111 | { src: '~/plugins/vue-good-table', ssr: false } 112 | ], 113 | ``` 114 | 115 | This should now work as expected. -------------------------------------------------------------------------------- /vp-docs/.vuepress/components/grouped-custom.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 94 | 95 | 125 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at anand.cooper@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /src/styles/_table-th.scss: -------------------------------------------------------------------------------- 1 | $sort-chevron-width: 5px; 2 | 3 | .vgt-table{ 4 | & th{ 5 | padding: .75em 1.5em .75em .75em; 6 | vertical-align: middle; 7 | position: relative; 8 | &.sortable{ 9 | button { 10 | -webkit-appearance: none; 11 | -moz-appearance: none; 12 | appearance: none; 13 | background: transparent; 14 | border: none; 15 | position: absolute; 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | height: 100%; 20 | &:focus{ 21 | outline: none; 22 | } 23 | &:after{ 24 | content: ''; 25 | position: absolute; 26 | height: 0px; 27 | width: 0px; 28 | right: 6px; 29 | top: 50%; 30 | margin-top: -7px; 31 | border-left: $sort-chevron-width solid transparent; 32 | border-right: $sort-chevron-width solid transparent; 33 | border-bottom: $sort-chevron-width solid $chevron-color; 34 | } 35 | &:before{ 36 | content: ''; 37 | position: absolute; 38 | height: 0px; 39 | width: 0px; 40 | right: 6px; 41 | top: 50%; 42 | margin-bottom: -7px; 43 | border-left: $sort-chevron-width solid transparent; 44 | border-right: $sort-chevron-width solid transparent; 45 | border-top: $sort-chevron-width solid $chevron-color; 46 | } 47 | } 48 | } 49 | } 50 | & th.line-numbers, & th.vgt-checkbox-col { 51 | padding: 0 .75em 0 .75em; 52 | color: $text-color; 53 | border-right: 1px solid $border-color; 54 | word-wrap: break-word; 55 | width: 25px; 56 | text-align: center; 57 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 58 | } 59 | & th.filter-th { 60 | padding: .75em .75em .75em .75em; 61 | } 62 | 63 | th.vgt-row-header{ 64 | border-bottom: 2px solid $border-color; 65 | border-top: 2px solid $border-color; 66 | background-color: lighten($border-color, 10%); 67 | .triangle { 68 | width: 24px; 69 | height: 24px; 70 | border-radius: 15%; 71 | position: relative; 72 | margin: 0px 8px; 73 | &:after { 74 | content: ''; 75 | position: absolute; 76 | display: block; 77 | left: 50%; 78 | top: 50%; 79 | margin-top: -6px; 80 | border-top: 6px solid transparent; 81 | border-bottom: 6px solid transparent; 82 | border-left: 6px solid $text-color; 83 | margin-left: -3px; 84 | transition: 0.3s ease transform; 85 | } 86 | &.expand:after { 87 | transform: rotate(90deg); 88 | } 89 | } 90 | } 91 | 92 | thead th{ 93 | color: $text-color; 94 | vertical-align: bottom; 95 | border-bottom: 1px solid $border-color; 96 | padding-right: 1.5em; 97 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 98 | &.vgt-checkbox-col{ 99 | vertical-align: middle; 100 | } 101 | &.sorting-asc button { 102 | &:after{ 103 | border-bottom: $sort-chevron-width solid $link-color; 104 | } 105 | } 106 | &.sorting-desc button { 107 | &:before{ 108 | border-top: $sort-chevron-width solid $link-color; 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /vp-docs/guide/configuration/search-options.md: -------------------------------------------------------------------------------- 1 | # Search Options 2 | 3 | Vue-good-table supports two ways of filtering the table. 4 | 1. A global search that searches through all records in the table 5 | 1. [Column filters](/guide/configuration/column-filter-options.md) that filter based on a given column 6 | 7 | This section talks about how to configure global search options. 8 | 9 | ```html 10 | 22 | 23 | ``` 24 | 25 | ## enabled 26 | 27 | type: `Boolean (default: false)` 28 | 29 | 30 | Allows a single search input for the whole table 31 | 32 | ::: warning 33 | Enabling this option disables column filters 34 | ::: 35 | ```html 36 | 42 | 43 | ``` 44 | 45 | 46 | ## trigger 47 | 48 | type: `String (default: '')` 49 | 50 | Allows you to specify if you want search to trigger on 'enter' event of the input. By **default table searches on key-up**. 51 | 52 | ```html 53 | 60 | 61 | ``` 62 | 63 | 64 | ## skipDiacritics 65 | 66 | type: `boolean (default: false)` 67 | 68 | By default, search does a diacriticless comparison so you can search through accented characters. This however slows down the search to some extent. If your data doesn't have accented characters, you can skip this check and gain some performance. 69 | 70 | ```html 71 | 78 | 79 | ``` 80 | 81 | ## searchFn 82 | 83 | type: `Function` 84 | 85 | Allows you to specify your own search function for the global search 86 | 87 | ```html 88 | 95 | 96 | ``` 97 | ```javascript 98 | // in js 99 | methods: { 100 | myFunc(row, col, cellValue, searchTerm){ 101 | return cellValue === 'my value'; 102 | }, 103 | } 104 | ``` 105 | 106 | ## placeholder 107 | 108 | type: `String (default: 'Search Table')` 109 | 110 | Text for global search input place holder 111 | ```html 112 | 119 | 120 | ``` 121 | 122 | ## externalQuery 123 | 124 | type: `String` 125 | 126 | 127 | If you want to use your own input for searching the table, you can use this property 128 | 129 | ```html 130 | 131 | 138 | 139 | ``` 140 | ```javascript 141 | // and in data 142 | data(){ 143 | return { 144 | searchTerm: '', 145 | // rows, columns etc... 146 | }; 147 | } 148 | ``` 149 | 150 | -------------------------------------------------------------------------------- /src/components/pagination/VgtPaginationPageInfo.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 130 | 131 | 134 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-good-table 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

404

That's a Four-Oh-Four.
16 | Take me home. 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/unit/specs/Table.spec.js: -------------------------------------------------------------------------------- 1 | import sinon from 'sinon' 2 | import { mount } from 'vue-test-utils' 3 | import VueGoodTable from '@/components/Table.vue' 4 | 5 | const columns = [ 6 | { 7 | label: 'Name', 8 | field: 'name' 9 | }, 10 | { 11 | label: 'Age', 12 | field: 'age', 13 | type: 'number' 14 | } 15 | ] 16 | const rows = [ 17 | {name: 'John', age: '20'}, 18 | {name: 'Jane', age: '24'}, 19 | {name: 'Susan', age: '16'}, 20 | {name: 'Chris', age: '55'}, 21 | {name: 'Dan', age: '40'}, 22 | {name: 'John', age: '20'}, 23 | {name: 'Jane', age: '24'}, 24 | {name: 'Susan', age: '16'}, 25 | {name: 'Chris', age: '55'}, 26 | {name: 'Dan', age: '40'} 27 | ] 28 | 29 | describe('Table.vue', () => { 30 | let wrapper, vm 31 | beforeEach(() => { 32 | wrapper = mount(VueGoodTable, { 33 | attachToDocument: true, 34 | propsData: { 35 | rows: rows, 36 | columns: columns 37 | } 38 | }) 39 | vm = wrapper.vm 40 | }) 41 | it('should render correct contents', (done) => { 42 | vm.$nextTick(() => { 43 | let tableRows = wrapper.findAll('tbody tr') 44 | tableRows.length.should.equal(rows.length) 45 | done() 46 | }) 47 | }) 48 | 49 | describe('global search', () => { 50 | it('should render less records', async () => { 51 | wrapper = mount(VueGoodTable, {propsData: { 52 | globalSearch: true, 53 | rows: rows, 54 | columns: columns}}) 55 | await wrapper.vm.$nextTick() 56 | var searchElt = wrapper.find('.global-search-input') 57 | searchElt.element.value = 'jo' 58 | searchElt.trigger('input') 59 | await wrapper.vm.$nextTick() 60 | let tableRows = wrapper.findAll('tbody tr') 61 | tableRows.length.should.be.below(rows.length) 62 | }) 63 | }) 64 | 65 | describe('sort', () => { 66 | let originalCompare 67 | beforeEach(() => { 68 | originalCompare = wrapper.vm.$data.dataTypes.number.compare 69 | }) 70 | 71 | afterEach(() => { 72 | wrapper.vm.$data.dataTypes.number.compare = originalCompare 73 | }) 74 | 75 | it('should call compare once per combination (touch each value at least once)', (done) => { 76 | var compareSpy = sinon.stub() 77 | vm.$data.dataTypes.number.compare = compareSpy 78 | vm.$nextTick(() => { 79 | vm.sort(1) 80 | vm.$nextTick(() => { 81 | compareSpy.callCount.should.be.above(rows.length - 2) 82 | done() 83 | }) 84 | }) 85 | }) 86 | 87 | it('should sort on the default by default', async () => { 88 | vm = mount(VueGoodTable, {propsData: {rows: rows, columns: columns, defaultSortBy: {field: 'age'}}}).vm 89 | await vm.$nextTick() 90 | vm.sortColumn.should.equal(1) 91 | }) 92 | 93 | it('should call sort if click on first header item', (done) => { 94 | let sortSpy = sinon.stub(vm, 'sort') 95 | vm.$nextTick(() => { 96 | vm.$el.querySelector('thead th').click() 97 | vm.$nextTick(() => { 98 | sortSpy.calledWith(0).should.be.true 99 | done() 100 | }) 101 | }) 102 | }) 103 | 104 | it('should call sort if click on second header item', async () => { 105 | let sortSpy = sinon.stub(vm, 'sort') 106 | await vm.$nextTick() 107 | vm.$el.querySelector('thead th:nth-child(2)').click() 108 | await vm.$nextTick() 109 | sortSpy.calledWith(1).should.be.true 110 | }) 111 | }) 112 | 113 | describe('filter', () => { 114 | it('should remove some rows when filtering', async () => { 115 | columns[0].filterable = true 116 | const wrapper = mount(VueGoodTable, {propsData: {rows: rows, columns: columns, paginated: false}}) 117 | const vm = wrapper.vm 118 | await vm.$nextTick() 119 | var searchElt = wrapper.find('input[type=text]') 120 | searchElt.element.value = 'jo' 121 | searchElt.trigger('input') 122 | await vm.$nextTick() 123 | setTimeout(() => { 124 | wrapper.findAll('tbody tr').length.should.be.below(rows.length).and.above(1) 125 | }, 420) 126 | }) 127 | }) 128 | }) 129 | -------------------------------------------------------------------------------- /src/components/VgtHeaderRow.vue: -------------------------------------------------------------------------------- 1 | 74 | 75 | 144 | 145 | 148 | -------------------------------------------------------------------------------- /dev/grouped-table.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 141 | 142 | 147 | -------------------------------------------------------------------------------- /src/styles/nocturnal/nocturnal.scss: -------------------------------------------------------------------------------- 1 | @import './overrides'; 2 | // suggested by wifey 3 | .vgt-table.nocturnal{ 4 | border: 1px solid $border-color; 5 | background-color: $table-bg; 6 | 7 | & tr.clickable { 8 | &:hover{ 9 | background-color: $highlight-color; 10 | } 11 | } 12 | 13 | // td 14 | & td { 15 | border-bottom: 1px solid $border-color; 16 | color: $text-color; 17 | } 18 | 19 | //th 20 | & th.line-numbers, & th.vgt-checkbox-col { 21 | color: $text-color; 22 | border-right: 1px solid $border-color; 23 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 24 | } 25 | thead th{ 26 | color: $text-color; 27 | border-bottom: 1px solid $border-color; 28 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 29 | &.sortable { 30 | // color: lighten($text-color, 15%); 31 | &:before{ 32 | border-top-color: $chevron-color; 33 | } 34 | &:after{ 35 | border-bottom-color: $chevron-color; 36 | } 37 | &.sorting-asc{ 38 | color: white; 39 | &:after{ 40 | border-bottom-color: $link-color; 41 | } 42 | } 43 | &.sorting-desc { 44 | color: white; 45 | &:before{ 46 | border-top-color: $link-color; 47 | } 48 | } 49 | } 50 | } 51 | 52 | //bordered 53 | &.bordered td, &.bordered th { 54 | border: 1px solid $border-color; 55 | } 56 | 57 | //input 58 | .vgt-input, .vgt-select{ 59 | color: $text-color; 60 | background-color: darken($thead-bg-color-2, 5%); 61 | border: 1px solid $input-border-color; 62 | &::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 63 | color: $text-color; 64 | opacity: 0.3; /* Firefox */ 65 | } 66 | } 67 | } 68 | 69 | .vgt-wrap.nocturnal{ 70 | .vgt-wrap__footer{ 71 | color: $text-color; 72 | border: 1px solid $border-color; 73 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 74 | .footer__row-count{ 75 | position: relative; 76 | &__label{ 77 | color: $secondary-text-color; 78 | } 79 | &__select{ 80 | color: $text-color; 81 | background: darken($thead-bg-color-2, 5%); 82 | border: none; 83 | -webkit-appearance: none; 84 | -moz-appearance: none; 85 | appearance: none; 86 | padding-right: 15px; 87 | padding-left: 10px; 88 | border-radius: 3px; 89 | text-align: center; 90 | &:focus{ 91 | border-color: $link-color; 92 | } 93 | } 94 | &::after{ 95 | content: ''; 96 | display: block; 97 | position: absolute; 98 | height: 0px; 99 | width: 0px; 100 | right: 6px; 101 | top: 50%; 102 | margin-top: -1px; 103 | border-top: 6px solid $text-color; 104 | border-left: 6px solid transparent; 105 | border-right: 6px solid transparent; 106 | border-bottom: none; 107 | pointer-events: none 108 | } 109 | } 110 | .footer__navigation{ 111 | &__page-btn{ 112 | color: $text-color; 113 | &.disabled, 114 | &.disabled:hover { 115 | .chevron.left:after{ 116 | border-right-color: $text-color; 117 | } 118 | .chevron.right:after{ 119 | border-left-color: $text-color; 120 | } 121 | } 122 | } 123 | &__info, &__page-info{ 124 | color: $secondary-text-color; 125 | } 126 | } 127 | } 128 | 129 | // control bar 130 | .vgt-global-search{ 131 | border: 1px solid $border-color; 132 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 133 | } 134 | .vgt-global-search__input{ 135 | .input__icon{ 136 | .magnifying-glass{ 137 | border: 2px solid darken($border-color, 2%); 138 | &:before{ 139 | background: darken($border-color, 2%); 140 | } 141 | } 142 | } 143 | .vgt-input, .vgt-select{ 144 | color: $text-color; 145 | background-color: darken($thead-bg-color-2, 5%); 146 | border: 1px solid $input-border-color; 147 | &::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 148 | color: $text-color; 149 | opacity: 0.3; /* Firefox */ 150 | } 151 | } 152 | } 153 | } -------------------------------------------------------------------------------- /src/styles/black-rhino/black-rhino.scss: -------------------------------------------------------------------------------- 1 | @import './overrides'; 2 | // suggested by wifey 3 | .vgt-table.black-rhino{ 4 | border: 1px solid $border-color; 5 | background-color: $table-bg; 6 | 7 | & tr.clickable { 8 | &:hover{ 9 | background-color: $highlight-color; 10 | } 11 | } 12 | 13 | // td 14 | & td { 15 | border-bottom: 1px solid $border-color-td; 16 | color: $text-color-td; 17 | } 18 | 19 | //th 20 | & th.line-numbers, & th.vgt-checkbox-col { 21 | color: $text-color; 22 | border-right: 1px solid $border-color; 23 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 24 | } 25 | thead th{ 26 | color: $text-color; 27 | text-shadow: 1px 1px $text-shadow-color; 28 | border-bottom: 1px solid $border-color; 29 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 30 | &.sortable { 31 | // color: lighten($text-color, 15%); 32 | &:before{ 33 | border-top-color: $chevron-color; 34 | } 35 | &:after{ 36 | border-bottom-color: $chevron-color; 37 | } 38 | &.sorting-asc{ 39 | color: white; 40 | &:after{ 41 | border-bottom-color: $link-color; 42 | } 43 | } 44 | &.sorting-desc { 45 | &:before{ 46 | border-top-color: $link-color; 47 | } 48 | } 49 | } 50 | } 51 | 52 | //bordered 53 | &.bordered td { 54 | border: 1px solid $border-color-td; 55 | } 56 | 57 | &.bordered th { 58 | border: 1px solid $border-color; 59 | } 60 | 61 | //input 62 | .vgt-input, .vgt-select{ 63 | color: $text-color; 64 | background-color: $input-bg; 65 | border: 1px solid $input-border-color; 66 | &::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 67 | color: $text-color; 68 | opacity: 0.3; /* Firefox */ 69 | } 70 | } 71 | } 72 | 73 | .vgt-wrap.black-rhino{ 74 | .vgt-wrap__footer{ 75 | color: $text-color; 76 | border: 1px solid $border-color; 77 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 78 | .footer__row-count{ 79 | position: relative; 80 | padding-right: 3px; 81 | &__label{ 82 | color: $secondary-text-color; 83 | } 84 | &__select{ 85 | color: $text-color-td; 86 | background: $input-bg; 87 | border: none; 88 | -webkit-appearance: none; 89 | -moz-appearance: none; 90 | appearance: none; 91 | padding-right: 15px; 92 | padding-left: 5px; 93 | border-radius: 3px; 94 | &::-ms-expand{ 95 | display: none; 96 | } 97 | &:focus{ 98 | border-color: $link-color; 99 | } 100 | } 101 | &::after{ 102 | content: ''; 103 | display: block; 104 | position: absolute; 105 | height: 0px; 106 | width: 0px; 107 | right: 6px; 108 | top: 50%; 109 | margin-top: -1px; 110 | border-top: 6px solid $text-color-td; 111 | border-left: 6px solid transparent; 112 | border-right: 6px solid transparent; 113 | border-bottom: none; 114 | pointer-events: none 115 | } 116 | } 117 | .footer__navigation{ 118 | &__page-btn{ 119 | color: $text-color; 120 | &.disabled, 121 | &.disabled:hover { 122 | .chevron.left:after{ 123 | border-right-color: $text-color; 124 | } 125 | .chevron.right:after{ 126 | border-left-color: $text-color; 127 | } 128 | } 129 | } 130 | &__info, &__page-info{ 131 | color: $text-color; 132 | } 133 | } 134 | } 135 | 136 | // control bar 137 | .vgt-global-search{ 138 | border: 1px solid $border-color; 139 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 140 | } 141 | .vgt-global-search__input{ 142 | .input__icon{ 143 | .magnifying-glass{ 144 | border: 2px solid darken($border-color, 2%); 145 | &:before{ 146 | background: darken($border-color, 2%); 147 | } 148 | } 149 | } 150 | .vgt-input, .vgt-select{ 151 | color: $text-color; 152 | background-color: darken($thead-bg-color-2, 5%); 153 | border: 1px solid $input-border-color; 154 | &::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 155 | color: $text-color; 156 | opacity: 0.3; /* Firefox */ 157 | } 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /src/styles/_table-footer.scss: -------------------------------------------------------------------------------- 1 | $footer-font-size: 1.1rem; 2 | 3 | .vgt-wrap__actions-footer{ 4 | border: 1px solid $border-color; 5 | } 6 | .vgt-wrap__footer{ 7 | color: $text-color; 8 | font-size: $footer-font-size; 9 | padding: 1em; 10 | border: 1px solid $border-color; 11 | background: linear-gradient($thead-bg-color-1, $thead-bg-color-2); 12 | .footer__row-count{ 13 | position: relative; 14 | padding-right: 3px; 15 | &__label, &__select{ 16 | display: inline-block; 17 | vertical-align: middle; 18 | } 19 | &__label{ 20 | font-size: $footer-font-size; 21 | } 22 | &__select{ 23 | font-size: $footer-font-size; 24 | background-color: transparent; 25 | width: auto; 26 | padding: 0; 27 | border: 0; 28 | border-radius: 0; 29 | height: auto; 30 | margin-left: 8px; 31 | color: $text-color; 32 | font-weight: bold; 33 | -webkit-appearance: none; 34 | -moz-appearance: none; 35 | appearance: none; 36 | padding-right: 15px; 37 | padding-left: 5px; 38 | &::-ms-expand{ 39 | display: none; 40 | } 41 | &:focus{ 42 | outline: none; 43 | border-color: $link-color; 44 | } 45 | } 46 | &::after{ 47 | content: ''; 48 | display: block; 49 | position: absolute; 50 | height: 0px; 51 | width: 0px; 52 | right: 6px; 53 | top: 50%; 54 | margin-top: -1px; 55 | border-top: 6px solid $text-color; 56 | border-left: 6px solid transparent; 57 | border-right: 6px solid transparent; 58 | border-bottom: none; 59 | pointer-events: none 60 | } 61 | } 62 | .footer__navigation{ 63 | > button:first-of-type { 64 | margin-right: 16px; 65 | } 66 | font-size: $footer-font-size; 67 | &__page-btn, &__info, &__page-info{ 68 | display: inline-block; 69 | vertical-align: middle; 70 | color: $secondary-text-color; 71 | } 72 | &__page-btn{ 73 | -webkit-appearance: none; 74 | -moz-appearance: none; 75 | appearance: none; 76 | background: transparent; 77 | border: none; 78 | text-decoration: none; 79 | color: $text-color; 80 | font-weight: bold; 81 | white-space:nowrap; 82 | vertical-align: middle; 83 | &:hover{ 84 | cursor: pointer; 85 | } 86 | &.disabled, 87 | &.disabled:hover { 88 | opacity: 0.5; 89 | cursor: not-allowed; 90 | .chevron.left:after{ 91 | border-right-color: $text-color; 92 | } 93 | .chevron.right:after{ 94 | border-left-color: $text-color; 95 | } 96 | } 97 | span{ 98 | display: inline-block; 99 | vertical-align: middle; 100 | font-size: $footer-font-size; 101 | } 102 | .chevron{ 103 | width: 24px; 104 | height: 24px; 105 | border-radius: 15%; 106 | position: relative; 107 | margin: 0; 108 | display: inline-block; 109 | vertical-align: middle; 110 | &:after{ 111 | content: ''; 112 | position: absolute; 113 | display: block; 114 | left: 50%; 115 | top: 50%; 116 | margin-top: -6px; 117 | border-top: 6px solid transparent; 118 | border-bottom: 6px solid transparent; 119 | } 120 | &.left::after{ 121 | border-right: 6px solid $link-color; 122 | margin-left: -3px; 123 | } 124 | 125 | &.right::after{ 126 | border-left: 6px solid $link-color; 127 | margin-left: -3px; 128 | } 129 | } 130 | } 131 | &__info, &__page-info{ 132 | display: inline-block; 133 | margin: 0px 16px; 134 | } 135 | &__page-info{ 136 | span{ 137 | display: inline-block; 138 | vertical-align: middle; 139 | } 140 | &__current-entry{ 141 | width: 30px; 142 | text-align: center; 143 | vertical-align: middle; 144 | display: inline-block; 145 | margin: 0px 10px; 146 | font-weight: bold; 147 | } 148 | } 149 | 150 | 151 | } 152 | } 153 | 154 | @media only screen and (max-width: 750px) { 155 | /* on small screens hide the info */ 156 | .vgt-wrap__footer .footer__navigation__info{ 157 | display: none; 158 | } 159 | .vgt-wrap__footer .footer__navigation__page-btn{ 160 | margin-left: 16px; 161 | } 162 | } -------------------------------------------------------------------------------- /vp-docs/guide/configuration/README.md: -------------------------------------------------------------------------------- 1 | --- 2 | sidebarDepth: 3 3 | --- 4 | 5 | # Table Options 6 | 7 | These options relate to the table as a whole 8 | 9 | ## columns 10 | 11 | type: `Array` 12 | 13 | Array containing objects that describe table columns. The column object itself can contain many [configurable properties](/guide/configuration/column-options.md). 14 | ```javascript 15 | [ 16 | { 17 | label: 'Name', 18 | field: 'name', 19 | } 20 | //... 21 | ] 22 | ``` 23 | 24 | ## rows 25 | 26 | type: `Array` 27 | 28 | Array containing row objects. Each row object contains data that will be displayed in the table row. 29 | ```javascript 30 | [ 31 | { 32 | id:1, 33 | name:"John", 34 | age:20 35 | }, 36 | //... 37 | ] 38 | ``` 39 | 40 | ::: tip 41 | for **grouped rows**, you need a nested format. Refer to [Grouped Table](/guide/advanced/grouped-table.md) for examples. 42 | ::: 43 | 44 | ## max-height 45 | 46 | type: `String` 47 | Set a maximum height for table body 48 | 49 | ```vue 50 | 54 | 55 | ``` 56 | 57 | ## fixed-header 58 | 59 | type: `Boolean (default: false)` 60 | fix header so it stays in view as you scroll the table. 61 | 62 | ```vue 63 | 68 | 69 | ``` 70 | 71 | 72 | ::: tip 73 | Fixed header should probably be used with max-height 74 | ::: 75 | 76 | 77 | ## line-numbers 78 | 79 | type: `Boolean (default: false)` 80 | Show line number for each row 81 | ```html 82 | 86 | 87 | ``` 88 | 89 | 90 | ## row-style-class 91 | 92 | type: `String` or `Function` 93 | 94 | property to assign a class to rows. This can either be a string representing a css class-name or a function. 95 | 96 | ```vue 97 | 101 | 102 | ``` 103 | 104 | ```js 105 | methods: { 106 | rowStyleClassFn(row) { 107 | return row.age > 18 ? 'green' : 'red'; 108 | }, 109 | } 110 | ``` 111 | 112 | 113 | ## rtl 114 | 115 | type: `Boolean (default: false)` 116 | 117 | Enable Right-To-Left layout for the table 118 | ```html 119 | 123 | 124 | ``` 125 | 126 | 127 | ## Table Actions Slot 128 | If you want to add table specific actions like a print button for example, you can use the Table Actions Slot. If you have global search enabled, the action panel will show up to the right of that. 129 | 130 | ::: tip Note 131 | You don't have to have global search enabled to use this slot. 132 | ::: 133 | 134 | ```html 135 | 138 |
139 | This will show up on the top right of the table. 140 |
141 |
142 | ``` 143 | 144 | 145 | 146 | ## Table Actions Footer Slot 147 | 148 | If you want a space for your buttons between pagination and the table. This is the slot you use. 149 | 150 | ```html 151 | 154 |
155 | This will show up on the bottom of the table. 156 |
157 |
158 | ``` 159 | 160 | ## Empty state slot 161 | You can provide html for empty state slot as well. Example: 162 | 163 | ```html 164 | 167 |
168 | This will show up when there are no rows 169 |
170 |
171 | ``` 172 | 173 | ## mode 174 | 175 | type: `String` 176 | 177 | Set mode=`remote` to allow sorting/filtering etc to be powered by server side instead of client side. 178 | 179 | for a detailed workflow example check out [Server Side Workflow](/guide/advanced/remote-workflow.md) 180 | 181 | ```html 182 | 186 | 187 | ``` 188 | 189 | ## totalRecords 190 | 191 | type: `Number` 192 | ::: tip 193 | totalRecords is only useful for remote mode. When server controls pagination the table needs to know how many total rows exist. 194 | ::: 195 | 196 | total number of rows that exist given a table/filter. refer to [remote workflow](/guide/advanced/remote-workflow.md) for more details 197 | 198 | ## compactMode 199 | 200 | type: `Boolean (default: false)` 201 | 202 | Enable mobile-friendly List view on small devices (screenSize below 576px) 203 | ```html 204 | 208 | 209 | ``` 210 | -------------------------------------------------------------------------------- /src/styles/polar-bear/polar-bear.scss: -------------------------------------------------------------------------------- 1 | @import './overrides'; 2 | // suggested by wifey 3 | .vgt-inner-wrap{ 4 | border-radius: 0.25rem; 5 | // box-shadow: 0 1px 3px rgba(50,50,93,.15), 0 1px 0 rgba(0,0,0,.02); 6 | box-shadow: 0 1px 3px 0 rgba(50,50,93,.1), 0 1px 2px 0 rgba(50,50,93,.06); 7 | } 8 | .vgt-table.polar-bear{ 9 | border-spacing: 0; 10 | border-collapse: separate; 11 | font-size: 1rem; 12 | background-color: $white; 13 | border: 1px solid $border-color; 14 | border-bottom: none; 15 | border-radius: 0.25rem; 16 | // td 17 | & td { 18 | padding: 1em .75em 1em .75em; 19 | border-bottom: 1px solid $border-color-td; 20 | color: $text-color-td; 21 | &.vgt-right-align{ 22 | text-align: right; 23 | } 24 | } 25 | 26 | //th 27 | & th.line-numbers, & th.vgt-checkbox-col { 28 | color: $text-color; 29 | border-right: 1px solid $border-color; 30 | background: $thead-bg-color-3; 31 | } 32 | thead th{ 33 | color: $header-color; 34 | font-weight: 600; 35 | // text-shadow: 1px 1px $text-shadow-color; 36 | border-bottom: 1px solid $border-color; 37 | background: $thead-bg-color-3; 38 | &.sorting-asc, &.sorting-desc { 39 | color: $link-color; 40 | } 41 | &.sorting-desc{ 42 | &:before{ 43 | border-top: 5px solid lighten($link-color, 5%); 44 | } 45 | } 46 | &.sorting-asc{ 47 | &:after{ 48 | border-bottom: 5px solid lighten($link-color, 5%); 49 | } 50 | } 51 | 52 | .vgt-input, .vgt-select{ 53 | height: 2.75em; 54 | box-shadow: 0 1px 2px 0 rgba(0,0,0,.05); 55 | border: 1px solid $border-color-td; 56 | } 57 | 58 | .vgt-input:focus, .vgt-select:focus { 59 | outline: 0; 60 | border-color: lighten($focus-color, 25%); 61 | } 62 | } 63 | thead tr:first-child{ 64 | th:first-child{ 65 | border-top-left-radius: 0.25rem; 66 | } 67 | th:last-child{ 68 | border-top-right-radius: 0.25rem; 69 | } 70 | } 71 | 72 | //bordered 73 | &.bordered td { 74 | border: 1px solid $border-color; 75 | background: $white; 76 | } 77 | 78 | &.bordered th { 79 | // border: none; 80 | border: 1px solid $border-color; 81 | } 82 | } 83 | 84 | .vgt-wrap.polar-bear{ 85 | .vgt-wrap__footer{ 86 | color: $text-color; 87 | border: 1px solid $border-color; 88 | border-bottom: 0px; 89 | border-top: 0px; 90 | background: linear-gradient($thead-bg-color-3, $thead-bg-color-3); 91 | .footer__row-count{ 92 | position: relative; 93 | padding-right: 3px; 94 | &__label{ 95 | color: $secondary-text-color; 96 | } 97 | &__select{ 98 | text-align: center; 99 | color: $text-color-td; 100 | background: $table-bg; 101 | border: none; 102 | -webkit-appearance: none; 103 | -moz-appearance: none; 104 | appearance: none; 105 | padding: 5px; 106 | padding-right: 30px; 107 | border-radius: 3px; 108 | box-shadow: 0 1px 2px 0 rgba(0,0,0,.05); 109 | border: 1px solid $border-color-td; 110 | &::-ms-expand{ 111 | display: none; 112 | } 113 | &:focus{ 114 | border-color: $link-color; 115 | } 116 | } 117 | &::after{ 118 | content: ''; 119 | display: block; 120 | position: absolute; 121 | height: 0px; 122 | width: 0px; 123 | right: 15px; 124 | top: 50%; 125 | margin-top: -3px; 126 | border-top: 6px solid $text-color-td; 127 | border-left: 6px solid transparent; 128 | border-right: 6px solid transparent; 129 | border-bottom: none; 130 | pointer-events: none 131 | } 132 | } 133 | .footer__navigation{ 134 | &__page-btn{ 135 | color: $text-color; 136 | &.disabled, 137 | &.disabled:hover { 138 | .chevron.left:after{ 139 | border-right-color: $text-color; 140 | } 141 | .chevron.right:after{ 142 | border-left-color: $text-color; 143 | } 144 | } 145 | } 146 | &__info, &__page-info{ 147 | color: $text-color; 148 | } 149 | } 150 | } 151 | 152 | // control bar 153 | .vgt-global-search{ 154 | border: 1px solid $border-color; 155 | border-bottom: 0px; 156 | border-top-left-radius: 3px; 157 | border-top-right-radius: 3px; 158 | background: $thead-bg-color-3; 159 | } 160 | .vgt-global-search__input{ 161 | .input__icon{ 162 | .magnifying-glass{ 163 | border: 2px solid darken($border-color, 2%); 164 | &:before{ 165 | background: darken($border-color, 2%); 166 | } 167 | } 168 | } 169 | .vgt-input, .vgt-select{ 170 | height: 2.75em; 171 | box-shadow: 0 1px 2px 0 rgba(0,0,0,.05); 172 | border: 1px solid $border-color-td; 173 | &::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */ 174 | color: $text-color; 175 | opacity: 0.3; /* Firefox */ 176 | } 177 | } 178 | } 179 | } -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-good-table 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
hero

vue-good-table

21 | A powerful and easy to use data table plugin for VueJS 22 |

Get Started →

Simple to Use

You get features like sorting / filtering / paging with minimal setup.

Advanced Customizations

Easily customize anything from table cells to column headers.

Performant

Creating performant client side tables has never been easier.

25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /vp-docs/guide/advanced/remote-workflow.md: -------------------------------------------------------------------------------- 1 | # Server Side Table 2 | 3 | ## Why Remote Mode? 4 | 5 | Vue-good-table's in-built features like sorting, paging, filtering etc. are all performed client side and therefore are great for most of the use-cases. Sometimes though, we might have **too much data to render all of it at once on the UI**. In such cases, we would want to do things like sorting, paging, filtering on the server side. Fortunately, vue-good-table comes with `remote mode` to switch from client side to server side. 6 | 7 | When remote mode is on, vue-good-table does not perform sorting, paging, filtering etc. on the client side but instead emits events that we can use to then send proper parameters to the back-end. The server then is expected to send the correct rows to display on the UI. 8 | 9 | Following is a workflow you can use to get a server powered vue-good-table instance: 10 | 11 | ## Prep Work 12 | ### What do we send to server? 13 | 14 | Before we dive into remote mode, lets agree on what we're going to be sending to the server. A set of parameters that tells the server exactly what rows I need to get back. Here's a proposed parameter object to send: 15 | 16 | ```js 17 | serverParams: { 18 | // a map of column filters example: {name: 'john', age: '20'} 19 | columnFilters: { 20 | }, 21 | sort: [ 22 | { 23 | field: '', // example: 'name' 24 | type: '' // 'asc' or 'desc' 25 | } 26 | ], 27 | 28 | page: 1, // what page I want to show 29 | perPage: 10 // how many items I'm showing per page 30 | } 31 | ``` 32 | With the above information, server should be able to generate the relevant rows to send back. 33 | 34 | ### What does the server send back? 35 | Two things are required for the server to send back 36 | 1. **relevant rows** - set of rows for the current page, matching the current filter and sort. 37 | 2. **totalRecords** - number of total records matching the params we sent (not just the current page). This is required for the pagination to work correctly. 38 | 39 | ## Set mode to remote 40 | 41 | ```html 42 | 50 | ``` 51 | this tells VGT to not do client side paging/sorting/filtering 52 | 53 | ## Provide handlers for user events 54 | 55 | Now instead of doing the above client side, each user interaction will generate events. So lets provide handlers for those events: 56 | ```html 57 | 70 | ``` 71 | 72 | ... in data 73 | ```javascript 74 | data() { 75 | return { 76 | isLoading: false, 77 | columns: [ 78 | //... 79 | ], 80 | rows: [], 81 | totalRecords: 0, 82 | serverParams: { 83 | columnFilters: { 84 | }, 85 | sort: [ 86 | { 87 | field: '', 88 | type: '' 89 | } 90 | ], 91 | page: 1, 92 | perPage: 10 93 | } 94 | }; 95 | }, 96 | ``` 97 | 98 | ... handlers 99 | 100 | ```javascript 101 | methods: { 102 | updateParams(newProps) { 103 | this.serverParams = Object.assign({}, this.serverParams, newProps); 104 | }, 105 | 106 | onPageChange(params) { 107 | this.updateParams({page: params.currentPage}); 108 | this.loadItems(); 109 | }, 110 | 111 | onPerPageChange(params) { 112 | this.updateParams({perPage: params.currentPerPage}); 113 | this.loadItems(); 114 | }, 115 | 116 | onSortChange(params) { 117 | this.updateParams({ 118 | sort: [{ 119 | type: params.sortType, 120 | field: this.columns[params.columnIndex].field, 121 | }], 122 | }); 123 | this.loadItems(); 124 | }, 125 | 126 | onColumnFilter(params) { 127 | this.updateParams(params); 128 | this.loadItems(); 129 | } 130 | 131 | // load items is what brings back the rows from server 132 | loadItems() { 133 | getFromServer(this.serverParams).then(response => { 134 | this.totalRecords = response.totalRecords; 135 | this.rows = response.rows; 136 | }); 137 | } 138 | } 139 | ``` 140 | 141 | ## So, what is happening? 142 | 1. Everytime the user interacts with the table, an appropriate event is emitted. 143 | 1. Along with this, VGT knows that this event will now result in fetching things from the backend. So it starts a loading screen. 144 | 1. In the handler of that event, we first update the `serverParams` and then send a request to the backend. 145 | 1. When we get the response back, we update both the totalRecords and the rows data objects. 146 | 1. Row object's update signifies to VGT that the loading event is now done, and VGT shows the new rows on the table. 147 | 148 | ::: tip 149 | If you want to show loading notification manually, you can do so using table's `:isLoading.sync="isLoading"` property. 150 | ::: 151 | 152 | ::: tip 153 | to style the loading dom, you can use the slot - `loadingContent` 154 | ::: 155 | 156 | ## Conclusion 157 | So that wasn't too bad. You now have VGT that's powered completely by your backend server. 158 | 159 | -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/2.bc66dc77.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[2],{191:function(t,a,s){"use strict";s.r(a);var n=s(0),e=Object(n.a)({},function(){var t=this.$createElement,a=this._self._c||t;return a("div",{staticClass:"content"},[this._m(0),this._m(1),this._m(2),a("theme-example"),this._m(3),this._m(4),a("theme-example",{attrs:{theme:"black-rhino"}}),this._m(5),this._m(6),a("theme-example",{attrs:{theme:"nocturnal"}})],1)},[function(){var t=this.$createElement,a=this._self._c||t;return a("h1",{attrs:{id:"themes"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#themes","aria-hidden":"true"}},[this._v("#")]),this._v(" Themes")])},function(){var t=this.$createElement,a=this._self._c||t;return a("h2",{attrs:{id:"default"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#default","aria-hidden":"true"}},[this._v("#")]),this._v(" Default")])},function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("<")]),t._v("vue-good-table")]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":columns")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("columns"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":rows")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("rows"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n"),s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])])},function(){var t=this.$createElement,a=this._self._c||t;return a("h2",{attrs:{id:"black-rhino"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#black-rhino","aria-hidden":"true"}},[this._v("#")]),this._v(" Black-rhino")])},function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("<")]),t._v("vue-good-table")]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":columns")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("columns"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":rows")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("rows"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v("theme")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("black-rhino"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n"),s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])])},function(){var t=this.$createElement,a=this._self._c||t;return a("h2",{attrs:{id:"nocturnal"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#nocturnal","aria-hidden":"true"}},[this._v("#")]),this._v(" Nocturnal")])},function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("<")]),t._v("vue-good-table")]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":columns")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("columns"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":rows")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("rows"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v("theme")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("nocturnal"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n"),s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])])}],!1,null,null,null);a.default=e.exports}}]); -------------------------------------------------------------------------------- /vp-docs/guide/advanced/grouped-table.md: -------------------------------------------------------------------------------- 1 | # Grouped Table 2 | 3 | To create grouped rows, you need two things. 4 | 5 | #### 1. Add group-options to table component 6 | 7 | ```html 8 | 15 | 16 | ``` 17 | 18 | #### 2. Make sure the rows are formatted correctly. Grouped rows need to be nested within header rows containing data rows in their children property. For example: 19 | 20 | ```js 21 | rows: [ 22 | { 23 | mode: 'span', // span means this header will span all columns 24 | label: 'Mammal', // this is the label that'll be used for the header 25 | html: false, // if this is true, label will be rendered as html 26 | children: [ 27 | { name: 'Elephant', diet: 'herbivore', count: 5 }, 28 | { name: 'Cat', diet: 'carnivore', count: 28 } 29 | ] 30 | } 31 | ]; 32 | ``` 33 | 34 | 35 | 36 | #### 3. Sometimes, you might want a summary row instead of a header row. For example, if you want to show total count for your group 37 | 38 | ```javascript 39 | rows: [ 40 | { 41 | name: 'Mammals Total', // this is the label that'll be used for the header 42 | diet: undefined, 43 | count: '', // total count will be displayed here 44 | children: [ 45 | { name: 'Elephant', diet: 'herbivore', count: 5 }, 46 | { name: 'Cat', diet: 'carnivore', count: 28 } 47 | ] 48 | } 49 | ]; 50 | ``` 51 | 52 | #### 4. If you want the header/summary row to show up at the bottom of the group, you can specify that in the group-options property of the table. 53 | 54 | ```html 55 | 63 | 64 | ``` 65 | 66 | 67 | 68 | #### 5. What if you wanted to add a total count in summary rows? 69 | 70 | In your column definition add a property, `headerField`. This is just like `field` property but for summary/header rows only. So lets say we wanted to add a **sum function** to this field. 71 | 72 | ```js 73 | // in columns 74 | { 75 | label: 'Count', 76 | field: 'count', 77 | headerField: this.sumCount, 78 | type: 'number', 79 | }, 80 | 81 | // in methods we define sumCount 82 | methods: { 83 | sumCount: function (rowObj) { 84 | console.log(rowObj); 85 | let sum = 0; 86 | for (let i = 0; i < rowObj.children.length; i++) { 87 | sum += rowObj.children[i].count; 88 | } 89 | return sum; 90 | }, 91 | }, 92 | 93 | ``` 94 | 95 | ## Customizing Header Row 96 | 97 | If you want more control over what the header row looks like, you can use slots the same way you [customize rows](/guide/advanced/#custom-row-template). For example if you want to add a button in the header row or something, this would be the way to do it. 98 | 99 | ### When mode is 'span' 100 | 101 | In this case, the header row spans across all columns 102 | 103 | ```vue 104 | 112 | 117 | 118 | ``` 119 | 120 | 121 | 122 | ### When mode is not 'span' 123 | 124 | In this case header row expects a value for each column 125 | 126 | ```vue 127 | 135 | 143 | 144 | ``` 145 | 146 | 147 | 148 | ::: tip 149 | 150 | - The original row object can be accessed via `props.row` 151 | - The column object can be accessed via `props.column` 152 | - You can access the formatted row data (for example - formatted date) via `props.formattedRow` 153 | ::: 154 | 155 | ## Collapsable Rows 156 | 157 | To allow the row to collapse and expand you can use the groupOption "collapsable". You can either pass in a boolean or a number. 158 | If `collapsable` is set to `true` then it will default to making the first column collapsable. Alternatively, you can specify the column index number. 159 | If you only add new rows to your table at the end, then the expanded or collapsed state of your rows will be maintained. 160 | However if you need to insert rows before the last one, you can pass in `rowKey` inside of `groupOptions` with a unique identifier for your rows. 161 | The expanded and collapsed state will then be maintained. 162 | ```html 163 | 173 | 174 | ``` 175 | To expand/collapse all you can use the method called `expandAll` or `collapseAll`. 176 | ```js 177 | this.$refs.myCustomTable.expandAll(); 178 | this.$refs.myCustomTable.collapseAll(); 179 | ``` 180 | 181 | * **Live Demo:** https://jsfiddle.net/nb6fcqs7 182 | 183 | -------------------------------------------------------------------------------- /vp-docs/guide/configuration/table-events.md: -------------------------------------------------------------------------------- 1 | # Table Events 2 | 3 | ## @on-row-click 4 | event emitted on table row click 5 | ```html 6 | 10 | ``` 11 | ```javascript 12 | methods: { 13 | onRowClick(params) { 14 | // params.row - row object 15 | // params.pageIndex - index of this row on the current page. 16 | // params.selected - if selection is enabled this argument 17 | // indicates selected or not 18 | // params.event - click event 19 | } 20 | } 21 | ``` 22 | 23 | ## @on-row-dblclick 24 | event emitted on table row click 25 | ```html 26 | 30 | ``` 31 | ```javascript 32 | methods: { 33 | onRowDoubleClick(params) { 34 | // params.row - row object 35 | // params.pageIndex - index of this row on the current page. 36 | // params.selected - if selection is enabled this argument 37 | // indicates selected or not 38 | // params.event - click event 39 | } 40 | } 41 | ``` 42 | 43 | ## @on-cell-click 44 | event emitted on table cell click 45 | ```html 46 | 50 | ``` 51 | ```javascript 52 | methods: { 53 | onCellClick(params) { 54 | // params.row - row object 55 | // params.column - column object 56 | // params.rowIndex - index of this row on the current page. 57 | // params.event - click event 58 | } 59 | } 60 | ``` 61 | 62 | ## @on-row-mouseenter 63 | event emitted on row mouseenter 64 | ```html 65 | 69 | ``` 70 | ```javascript 71 | methods: { 72 | onRowMouseover(params) { 73 | // params.row - row object 74 | // params.pageIndex - index of this row on the current page. 75 | } 76 | } 77 | ``` 78 | 79 | ## @on-row-mouseleave 80 | event emitted on table row mouseleave 81 | ```html 82 | 86 | ``` 87 | ```javascript 88 | methods: { 89 | onRowMouseleave(row, pageIndex) { 90 | // row - row object 91 | // pageIndex - index of this row on the current page. 92 | } 93 | } 94 | ``` 95 | 96 | ## @on-search 97 | event emitted on global search (when global search is enabled) 98 | ```html 99 | 103 | ``` 104 | ```javascript 105 | methods: { 106 | onSearch(params) { 107 | // params.searchTerm - term being searched for 108 | // params.rowCount - number of rows that match search 109 | } 110 | } 111 | ``` 112 | 113 | ## @on-page-change 114 | event emitted on pagination page change (when pagination is enabled) 115 | ```html 116 | 120 | ``` 121 | ```javascript 122 | methods: { 123 | onPageChange(params) { 124 | // params.currentPage - current page that pagination is at 125 | // params.prevPage - previous page 126 | // params.currentPerPage - number of items per page 127 | // params.total - total number of items in the table 128 | } 129 | } 130 | ``` 131 | 132 | ## @on-per-page-change 133 | event emitted on per page dropdown change (when pagination is enabled) 134 | ```html 135 | 139 | ``` 140 | ```javascript 141 | methods: { 142 | onPageChange(params) { 143 | // params.currentPage - current page that pagination is at 144 | // params.currentPerPage - number of items per page 145 | // params.total - total number of items in the table 146 | } 147 | } 148 | ``` 149 | 150 | ## @on-sort-change 151 | event emitted on sort change. 152 | ::: tip 153 | vue-good-table now supports sorting by multiple columns, so the params 154 | is an array. 155 | ::: 156 | 157 | ```html 158 | 162 | ``` 163 | ```javascript 164 | methods: { 165 | onSortChange(params) { 166 | // params[0].sortType - ascending or descending 167 | // params[0].columnIndex - index of column being sorted 168 | } 169 | } 170 | ``` 171 | 172 | 173 | ## @on-column-filter 174 | event emitted when column is filtered (only emitted for remote mode) 175 | ```html 176 | 180 | ``` 181 | ```javascript 182 | methods: { 183 | onColumnFilter(params) { 184 | // params.columnFilters - filter values for each column in the following format: 185 | // {field1: 'filterTerm', field3: 'filterTerm2') 186 | } 187 | } 188 | ``` 189 | 190 | ## @on-select-all 191 | event emitted when all is selected (only emitted for checkbox tables) 192 | ```html 193 | 198 | ``` 199 | ```javascript 200 | methods: { 201 | onSelectAll(params) { 202 | // params.selected - whether the select-all checkbox is checked or unchecked 203 | // params.selectedRows - all rows that are selected (this page) 204 | } 205 | } 206 | ``` 207 | 208 | ## @on-selected-rows-change 209 | event emitted whenever selection is changed (on checkbox tables) 210 | ```html 211 | 216 | ``` 217 | ```javascript 218 | methods: { 219 | selectionChanged(params) { 220 | // params.selectedRows - all rows that are selected (this page) 221 | } 222 | } 223 | ``` -------------------------------------------------------------------------------- /vp-docs/.vuepress/dist/assets/js/4.df9755ec.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([[4],{193:function(t,a,s){"use strict";s.r(a);var n=s(0),e=Object(n.a)({},function(){this.$createElement;this._self._c;return this._m(0)},[function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("div",{staticClass:"content"},[s("h1",{attrs:{id:"sort-options"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#sort-options","aria-hidden":"true"}},[t._v("#")]),t._v(" Sort Options")]),s("p",[t._v("Set of options related to table sorting")]),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("<")]),t._v("vue-good-table")]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":columns")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("columns"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":rows")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("rows"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":sort-options")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("{\n enabled: true,\n initialSortBy: {field: "),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v("name"),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v(", type: "),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v("asc"),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v("}\n }"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n"),s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"enabled"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#enabled","aria-hidden":"true"}},[t._v("#")]),t._v(" enabled")]),s("p",[t._v("type: "),s("code",[t._v("Boolean (default: true)")])]),s("p",[t._v("Enable/disable sorting on table as a whole.")]),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("<")]),t._v("vue-good-table")]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":columns")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("columns"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":rows")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("rows"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":sort-options")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("{\n enabled: true,\n }"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n"),s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])]),s("h2",{attrs:{id:"initialsortby"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#initialsortby","aria-hidden":"true"}},[t._v("#")]),t._v(" initialSortBy")]),s("p",[t._v("type: "),s("code",[t._v("Object")])]),s("p",[t._v("Allows specifying a default sort for the table on wakeup")]),s("div",{staticClass:"language-html extra-class"},[s("pre",{pre:!0,attrs:{class:"language-html"}},[s("code",[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("<")]),t._v("vue-good-table")]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":columns")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("columns"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":rows")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("rows"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),t._v("\n "),s("span",{attrs:{class:"token attr-name"}},[t._v(":sort-options")]),s("span",{attrs:{class:"token attr-value"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("=")]),s("span",{attrs:{class:"token punctuation"}},[t._v('"')]),t._v("{\n enabled: true,\n initialSortBy: {field: "),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v("name"),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v(", type: "),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v("asc"),s("span",{attrs:{class:"token punctuation"}},[t._v("'")]),t._v("}\n }"),s("span",{attrs:{class:"token punctuation"}},[t._v('"')])]),s("span",{attrs:{class:"token punctuation"}},[t._v(">")])]),t._v("\n"),s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token tag"}},[s("span",{attrs:{class:"token punctuation"}},[t._v("")])]),t._v("\n")])])])])}],!1,null,null,null);a.default=e.exports}}]); --------------------------------------------------------------------------------