├── .eslintignore
├── .browserslistrc
├── .firebaserc
├── .npmrc
├── postcss.config.js
├── babel.config.js
├── tests
└── unit
│ ├── .eslintrc.js
│ ├── TableServer.spec.js
│ ├── Pagination.spec.js
│ └── Client.spec.js
├── dist
├── demo.html
├── EnaTableClient
│ ├── demo.html
│ └── EnaTableClient.css
├── EnaTableServer
│ ├── demo.html
│ ├── EnaTableServer.css
│ └── EnaTableServer.umd.min.js
└── EnaTable.css
├── proj.code-workspace
├── proj.sublime-project
├── src
├── main.js
├── components
│ ├── mixins
│ │ ├── filters.js
│ │ ├── ActionsCell.vue
│ │ ├── methods.js
│ │ ├── default-props.js
│ │ └── Pagination.vue
│ ├── entry.js
│ ├── Server.vue
│ └── Client.vue
└── App.vue
├── .editorconfig
├── .gitignore
├── firebase.json
├── public
└── index.html
├── functions
└── countries.js
├── LICENSE
├── vue.config.js
├── .circleci
└── config.yml
├── CONTRIBUTING.md
├── .eslintrc.js
├── package.json
└── README.md
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules/*
2 | public/*
3 | dist/*
4 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not ie <= 10
4 |
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "vue-myena-table"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | # install as dev by default
2 | save-dev = true
3 | registry=https://registry.npmjs.org
4 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | },
5 | };
6 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset',
4 | ],
5 | };
6 |
--------------------------------------------------------------------------------
/tests/unit/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | mocha: true,
4 | },
5 | rules: {
6 | 'no-unused-expressions': 'off',
7 | },
8 | };
9 |
--------------------------------------------------------------------------------
/dist/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
EnaTable demo
3 |
4 |
5 |
6 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/proj.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "."
5 | },
6 | {
7 | "path": "C:\\Users\\andyg\\hobby\\myena-advanced-select"
8 | }
9 | ],
10 | "settings": {
11 | "npm-scripts.showStartNotification": false
12 | }
13 | }
--------------------------------------------------------------------------------
/proj.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "folders":
3 | [
4 | {
5 | "path": "."
6 | }
7 | ],
8 | "settings": {
9 | "SublimeLinter.linters.eslint.disable": false,
10 | "SublimeLinter.linters.eslint.selector": "text.html.vue, source.js - meta.attribute-with-value"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | import 'bootstrap/dist/css/bootstrap.css';
4 | import 'font-awesome/css/font-awesome.min.css';
5 |
6 | import App from './App.vue';
7 |
8 | Vue.config.productionTip = false;
9 |
10 | new Vue({
11 | render: h => h(App),
12 | }).$mount('#app');
13 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | indent_style = tab
14 | trim_trailing_whitespace = false
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 | # local env files
5 | .env.local
6 | .env.*.local
7 |
8 | # Log files
9 | npm-debug.log*
10 | yarn-debug.log*
11 | yarn-error.log*
12 |
13 | # Editor directories and files
14 | .idea
15 | .vscode
16 | *.suo
17 | *.ntvs*
18 | *.njsproj
19 | *.sln
20 | *.sw*
21 |
22 | /proj.sublime-workspace
23 |
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "example",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ],
9 | "rewrites": [
10 | {
11 | "source": "**",
12 | "destination": "/index.html"
13 | }
14 | ]
15 | },
16 | "functions": {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/mixins/filters.js:
--------------------------------------------------------------------------------
1 | export default {
2 | filters: {
3 | heading(key, headings) {
4 | if (undefined !== headings[key]) {
5 | return headings[key];
6 | }
7 | const firstUpper = w => w.charAt(0).toUpperCase() + w.slice(1);
8 | return key.split('_').map(firstUpper).join(' ');
9 | },
10 | format: (str, ...args) => [...args].reduce((s, a) => s.replace(/%s/, a), str),
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/dist/EnaTableClient/demo.html:
--------------------------------------------------------------------------------
1 |
2 | EnaTableClient demo
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/dist/EnaTableServer/demo.html:
--------------------------------------------------------------------------------
1 |
2 | EnaTableServer demo
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/src/components/entry.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Server from './Server.vue';
3 | import Client from './Client.vue';
4 |
5 | const components = {
6 | Server,
7 | Client,
8 | };
9 |
10 | // global register components
11 | function register() {
12 | Object.keys(components).forEach(name => Vue.component(
13 | `${LIBNAME}${name}`,
14 | components[name],
15 | {
16 | name: `${LIBNAME}${name}`,
17 | }
18 | ));
19 | }
20 |
21 | export {
22 | Server,
23 | Client,
24 | };
25 |
26 | export default register;
27 |
--------------------------------------------------------------------------------
/tests/unit/TableServer.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { shallowMount } from '@vue/test-utils';
3 | import Server from '@/components/Server.vue';
4 |
5 | describe('Server.vue', () => {
6 | it('renders a table with 1 row', () => {
7 | const wrapper = shallowMount(Server, {
8 | propsData: {
9 | },
10 | methods: {
11 | fetch() {
12 | return {
13 | data: [{ first_name: '1', id: 1 }],
14 | total: 1,
15 | };
16 | },
17 | },
18 | });
19 | expect(wrapper.contains('table tbody tr')).to.be.true;
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%=LIBNAME%>
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/functions/countries.js:
--------------------------------------------------------------------------------
1 | const countries = require('./countries.json');
2 |
3 | const collator = new Intl.Collator('en', { sensitivity: 'base', numeric: true });
4 |
5 | exports.handler = (event, context, callback) => {
6 | // your server-side functionality
7 | const { page = 1, per_page: perPage = 10, sort_by: sortBy = 'name', sort_dir: sortDir = 1, filter = {} } = event.queryStringParameters;
8 | // filter
9 | const filtered = countries.filter((c) => !filter.name
10 | || (filter.name && c.name.toLowerCase().indexOf(filter.name.toLowerCase()) !== -1));
11 | // sort
12 | filtered.sort((a, b) => sortDir * collator.compare(a[sortBy], b[sortBy]));
13 | // slice & send
14 | const start = (page - 1) * perPage;
15 | const end = start + parseInt(perPage, 10);
16 | callback(null, {
17 | statusCode: 200,
18 | body: JSON.stringify({
19 | list: filtered.slice(start, end),
20 | total: filtered.length,
21 | }),
22 | });
23 | };
24 |
--------------------------------------------------------------------------------
/src/components/mixins/ActionsCell.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018 Education Networks of America
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.
--------------------------------------------------------------------------------
/src/components/mixins/methods.js:
--------------------------------------------------------------------------------
1 | export default {
2 | computed: {
3 | allColumns() {
4 | const allColumns = this.columns.slice();
5 | if (!this.columns.includes('actions') && this.opts.detailsRow) {
6 | allColumns.push('actions');
7 | }
8 | return allColumns;
9 | },
10 | computedRowClasses() {
11 | return Object.values(this.pageData).map((rowGroup) => {
12 | return rowGroup.map((row) => {
13 | const classes = {};
14 | Object.keys(this.opts.rowClasses).forEach((prop) => {
15 | if (row[prop]) {
16 | classes[this.opts.rowClasses[prop]] = true;
17 | }
18 | });
19 | return classes;
20 | });
21 | });
22 | },
23 | colspan() {
24 | return this.allColumns.length;
25 | },
26 | },
27 | methods: {
28 | isShown(key) {
29 | return typeof this.shown[key] === 'undefined' || this.shown[key];
30 | },
31 | toggleRow(id) {
32 | this.expandedRows[id] = !this.expandedRows[id];
33 | this.expandedRows = Object.assign({}, this.expandedRows);
34 | this.$emit('toggleRow', id, this.expandedRows);
35 | },
36 | isRowExpanded(id) {
37 | return this.expandedRows[id];
38 | },
39 | },
40 | };
41 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const pkg = require('./package.json');
3 |
4 | module.exports = {
5 | css: {
6 | loaderOptions: {
7 | css: {
8 | // localIdentName: `${pkg.libname}[name]_[local]_[hash:base64:5]`,
9 | },
10 | },
11 | },
12 | lintOnSave: false,
13 | configureWebpack: (/* config */) => {
14 | const customConfig = {
15 | plugins: [
16 | new webpack.ProvidePlugin({
17 | $: 'jquery',
18 | jquery: 'jquery',
19 | jQuery: 'jquery',
20 | 'window.jquery': 'jquery',
21 | 'window.jQuery': 'jquery',
22 | 'window.$': 'jquery',
23 | }),
24 | new webpack.DefinePlugin({
25 | LIBNAME: JSON.stringify(pkg.libname),
26 | }),
27 | ],
28 | };
29 | // config for lib
30 | if (process.env.VUE_CLI_BUILD_TARGET === 'lib') {
31 | // set external modules so they won't get bundled with the lib
32 | customConfig.externals = [
33 | 'bootbox',
34 | 'bootstrap',
35 | 'font-awesome',
36 | 'jquery',
37 | 'vue',
38 | ];
39 | }
40 | // config parameter can be mutated
41 | // or a new object (to be used with webpack-merge) returned
42 | return customConfig;
43 | },
44 | };
45 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Javascript Node CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | install:
8 | docker:
9 | - image: circleci/node:10.13.0
10 |
11 | working_directory: ~/repo
12 |
13 | steps:
14 | - checkout
15 |
16 | # Download and cache dependencies
17 | - restore_cache:
18 | keys:
19 | - v1-dependencies-{{ checksum "package-lock.json" }}
20 | # fallback to using the latest cache if no exact match is found
21 | - v1-dependencies-
22 |
23 | - run: npm ci
24 |
25 | - save_cache:
26 | paths:
27 | - node_modules
28 | key: v1-dependencies-{{ checksum "package-lock.json" }}
29 |
30 | - save_cache:
31 | key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
32 | paths:
33 | - ~/repo
34 | test:
35 | docker:
36 | - image: circleci/node:10.13.0
37 |
38 | working_directory: ~/repo
39 |
40 | steps:
41 | - restore_cache:
42 | key: v1-repo-{{ .Environment.CIRCLE_SHA1 }}
43 | # run tests!
44 | - run: npm run test:unit
45 |
46 | workflows:
47 | version: 2
48 |
49 | install-and-test:
50 | jobs:
51 | - install
52 | - test:
53 | requires:
54 | - install
55 |
--------------------------------------------------------------------------------
/dist/EnaTableClient/EnaTableClient.css:
--------------------------------------------------------------------------------
1 | .Pagination_pagination_1xsiO{margin:0}.Pagination_pagination_1xsiO>li>span,.Pagination_pagination_1xsiO>li>span:focus,.Pagination_pagination_1xsiO>li>span:hover{border-top:1px solid transparent;border-bottom:1px solid transparent}.Pagination_pagination_1xsiO>li>span:focus,.Pagination_pagination_1xsiO>li>span:hover{background-color:#fff}.Pagination_info_2cUbo{float:right}.Pagination_info_2cUbo .Pagination_perPageSelector_CN8cp{margin-left:10px;margin-right:10px}.Client_table_30YmA{border-bottom:none}.Client_table_30YmA>thead:first-child>tr:first-child>th{border-top:1px solid #333;border-bottom:1px solid #333}.Client_table_30YmA>thead:first-child>tr:first-child>th a{cursor:default;color:inherit;text-decoration:none;display:block}.Client_table_30YmA>thead:first-child>tr:first-child>th.Client_sortable_pJAaM a{cursor:pointer}.Client_table_30YmA>thead:first-child>tr:first-child>th.Client_sortable_pJAaM a:focus{text-decoration:underline}.Client_table_30YmA>thead:first-child>tr:first-child>th.Client_sortable_pJAaM i{margin-top:5px;margin-left:5px}.Client_table_30YmA tbody>tr:first-child>th{background-color:#f2f2f2}.Client_table_30YmA tbody>tr:first-child>th a+span{margin-left:5px}.Client_table_30YmA tbody>tr:first-child>th a{color:#333;font-size:16px;display:inline-block;width:20px;text-align:center}.Client_table_30YmA .Client_checkbox_2krmy{margin:0}.Client_table_30YmA .Client_checkbox_2krmy label{min-height:18px}td.Client_selectable_3NYta:hover{cursor:pointer}
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to contribute
2 |
3 | :+1::tada: Thanks for taking the time to contribute! :tada::+1:
4 |
5 | ## Development guidelines
6 |
7 | * Checkout the repo, install dependencies and serve the example code with `npm run serve`
8 |
9 | * You can work on the components code under `src/components`.
10 |
11 | * You can work on the example code that uses the components is in `App.vue`. This code is what is served on the Demo page
12 |
13 | * Make sure to have ESLint enabled and fix all lint errors before pushing the code.
14 |
15 | #### **Did you find a bug or have a suggestion for a feature?**
16 |
17 | * **Ensure the bug/feature was not already reported** by searching on GitHub under [Issues](https://github.com/myENA/vue-table/issues).
18 |
19 | * If you're unable to find an open issue addressing the problem, [open a new one](https://github.com/myENA/vue-table/issues/new). Be sure to include a **title and clear description**, as much relevant information as possible, optionally a **code sample** or an **executable test case** demonstrating the expected behavior that is not occurring.
20 |
21 | #### **Did you write a patch that fixes a bug or adds a feature?**
22 |
23 | * Ensure the existing unit tests pass, with `npm run test:unit`. Write new or adapt the existing ones to cover the change.
24 |
25 | * Open a new GitHub pull request with the patch.
26 |
27 | * Ensure the PR description clearly describes the problem and solution. Include the relevant issue number if applicable.
28 |
29 | * Make sure to adapt the existing examples, as applicable.
30 |
31 |
--------------------------------------------------------------------------------
/dist/EnaTableServer/EnaTableServer.css:
--------------------------------------------------------------------------------
1 | .Pagination_pagination_1xsiO{margin:0}.Pagination_pagination_1xsiO>li>span,.Pagination_pagination_1xsiO>li>span:focus,.Pagination_pagination_1xsiO>li>span:hover{border-top:1px solid transparent;border-bottom:1px solid transparent}.Pagination_pagination_1xsiO>li>span:focus,.Pagination_pagination_1xsiO>li>span:hover{background-color:#fff}.Pagination_info_2cUbo{float:right}.Pagination_info_2cUbo .Pagination_perPageSelector_CN8cp{margin-left:10px;margin-right:10px}.Server_table_1-Jbh{border-bottom:none}.Server_table_1-Jbh>thead:first-child>tr:first-child>th{border-top:1px solid #333;border-bottom:1px solid #333}.Server_table_1-Jbh>thead:first-child>tr:first-child>th a{cursor:default;color:inherit;text-decoration:none;display:block}.Server_table_1-Jbh>thead:first-child>tr:first-child>th.Server_sortable_351RP a{cursor:pointer}.Server_table_1-Jbh>thead:first-child>tr:first-child>th.Server_sortable_351RP a:focus{text-decoration:underline}.Server_table_1-Jbh>thead:first-child>tr:first-child>th.Server_sortable_351RP i{margin-top:5px;margin-left:5px}.Server_table_1-Jbh tbody>tr:first-child>th{background-color:#f2f2f2}.Server_table_1-Jbh tbody>tr:first-child>th a+span{margin-left:5px}.Server_table_1-Jbh tbody>tr:first-child>th a{color:#333;font-size:16px;display:inline-block;width:20px;text-align:center}.Server_table_1-Jbh .Server_checkbox_1lyNb{margin:0}.Server_table_1-Jbh .Server_checkbox_1lyNb label{min-height:18px}.Server_pagination_3erRE{margin:0}.Server_info_2gbZL{float:right}.Server_info_2gbZL .Server_perPageSelector_3GVN9{margin-left:10px;margin-right:10px}
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | },
6 | extends: [
7 | 'plugin:vue/essential',
8 | '@vue/airbnb',
9 | ],
10 | rules: {
11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
13 | 'comma-dangle': ['error', {
14 | arrays: 'always-multiline',
15 | objects: 'always-multiline',
16 | imports: 'always-multiline',
17 | exports: 'always-multiline',
18 | functions: 'never',
19 | }],
20 | 'import/no-extraneous-dependencies': ['error', {
21 | devDependencies: true,
22 | optionalDependencies: false,
23 | peerDependencies: false,
24 | }],
25 | 'linebreak-style': ['off'],
26 | 'no-mixed-operators': ['error', {
27 | groups: [
28 | ['&', '|', '^', '~', '<<', '>>', '>>>'],
29 | ['==', '!=', '===', '!==', '>', '>=', '<', '<='],
30 | ['&&', '||'],
31 | ['in', 'instanceof'],
32 | ],
33 | allowSamePrecedence: true,
34 | }],
35 | 'no-param-reassign': ['error', {
36 | props: true,
37 | ignorePropertyModificationsFor: [
38 | 'state',
39 | 'acc',
40 | ],
41 | }],
42 | 'object-curly-newline': ['error', {
43 | ObjectExpression: { consistent: true },
44 | ObjectPattern: { multiline: true },
45 | }],
46 | 'template-curly-spacing': 'off',
47 | indent: [
48 | 'error', 2,
49 | { ignoredNodes: ['TemplateLiteral'] }
50 | ],
51 | },
52 | parserOptions: {
53 | parser: 'babel-eslint',
54 | },
55 | globals: {
56 | LIBNAME: true,
57 | },
58 | };
59 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@myena/vue-table",
3 | "version": "0.16.15",
4 | "description": "Vue Table components (client/server) used in ENA projects",
5 | "author": "Andy Ghiuta ",
6 | "scripts": {
7 | "serve": "vue-cli-service serve --host localhost",
8 | "build": "node build.js",
9 | "test:unit": "vue-cli-service test:unit",
10 | "lint": "vue-cli-service lint",
11 | "build:example": "vue-cli-service build --dest example",
12 | "postversion": "git push && git push --tags && echo Run: \"npm publish\"",
13 | "preversion": "npm run test:unit && npm run build && git add -A dist",
14 | "test:unitw": "vue-cli-service test:unit --watch"
15 | },
16 | "main": "dist/index.js",
17 | "files": [
18 | "dist/*",
19 | "src/components/*"
20 | ],
21 | "dependencies": {
22 | "core-js": "^3.6.4",
23 | "ramda": "^0.28.0"
24 | },
25 | "devDependencies": {
26 | "@vue/cli-plugin-babel": "^4.3.1",
27 | "@vue/cli-plugin-eslint": "^4.3.1",
28 | "@vue/cli-plugin-unit-mocha": "^4.3.1",
29 | "@vue/cli-service": "^4.3.1",
30 | "@vue/eslint-config-airbnb": "^5.0.2",
31 | "@vue/test-utils": "^1.0.0-beta.29",
32 | "axios": "^0.26.1",
33 | "babel-eslint": "^10.1.0",
34 | "bootstrap": "^3.4.1",
35 | "chai": "^4.1.2",
36 | "eslint": "^6.7.2",
37 | "eslint-plugin-import": "^2.20.2",
38 | "eslint-plugin-vue": "^6.2.2",
39 | "firebase-tools": "^6.10.0",
40 | "font-awesome": "^4.7.0",
41 | "glob": "^7.1.3",
42 | "jquery": "^3.4.1",
43 | "less": "^3.0.4",
44 | "less-loader": "^4.1.0",
45 | "qs": "^6.6.0",
46 | "vue": "^2.6.11",
47 | "vue-template-compiler": "^2.6.11"
48 | },
49 | "peerDependencies": {
50 | "axios": "^0.26.1",
51 | "bootstrap": "^3.3.7",
52 | "font-awesome": "^4.7.0",
53 | "jquery": "^3.3.1",
54 | "vue": "^2.6.10"
55 | },
56 | "keywords": [
57 | "vue",
58 | "table"
59 | ],
60 | "libname": "EnaTable",
61 | "license": "MIT",
62 | "repository": "github:myENA/vue-table"
63 | }
64 |
--------------------------------------------------------------------------------
/tests/unit/Pagination.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { shallowMount } from '@vue/test-utils';
3 | import Pagination from '@/components/mixins/Pagination.vue';
4 |
5 | const propsData = {
6 | text: {
7 | prev: '',
8 | next: '',
9 | info: {
10 | showing: 'Showing %s to %s of %s rows.',
11 | records: 'records per page',
12 | noRows: 'No rows to display',
13 | },
14 | },
15 | pageInterval: 7,
16 | perPage: 1,
17 | perPageValues: [1],
18 | currentPage: 1,
19 | totalRows: 1,
20 | };
21 | describe('Pagination', () => {
22 | it('is rendered', () => {
23 | const wrapper = shallowMount(Pagination, {
24 | propsData,
25 | });
26 | expect(wrapper.contains('div')).to.be.true;
27 | });
28 | it('Shows correct pages', () => {
29 | const wrapper = shallowMount(Pagination, {
30 | propsData,
31 | });
32 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([]);
33 | wrapper.setProps({ totalRows: 7, currentPage: 4 });
34 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([2, 3, 4, 5, 6]);
35 | wrapper.setProps({ totalRows: 10, currentPage: 1 });
36 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([2, 3, 4, 5, 6, 7, 8]);
37 | wrapper.setProps({ currentPage: 2 });
38 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([2, 3, 4, 5, 6, 7, 8]);
39 | wrapper.setProps({ currentPage: 3 });
40 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([2, 3, 4, 5, 6, 7, 8]);
41 | wrapper.setProps({ currentPage: 4 });
42 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([2, 3, 4, 5, 6, 7, 8]);
43 | wrapper.setProps({ currentPage: 5 });
44 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([2, 3, 4, 5, 6, 7, 8]);
45 | wrapper.setProps({ currentPage: 6 });
46 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([3, 4, 5, 6, 7, 8, 9]);
47 | wrapper.setProps({ currentPage: 7 });
48 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([3, 4, 5, 6, 7, 8, 9]);
49 | wrapper.setProps({ currentPage: 8 });
50 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([3, 4, 5, 6, 7, 8, 9]);
51 | wrapper.setProps({ currentPage: 9 });
52 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([3, 4, 5, 6, 7, 8, 9]);
53 | wrapper.setProps({ currentPage: 10 });
54 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([3, 4, 5, 6, 7, 8, 9]);
55 | wrapper.setProps({ totalRows: 14, currentPage: 9 });
56 | expect(wrapper.vm.pagesToShow).to.be.deep.equal([6, 7, 8, 9, 10, 11, 12]);
57 | });
58 | });
59 |
--------------------------------------------------------------------------------
/dist/EnaTable.css:
--------------------------------------------------------------------------------
1 | .Pagination_pagination_1xsiO{margin:0}.Pagination_pagination_1xsiO>li>span,.Pagination_pagination_1xsiO>li>span:focus,.Pagination_pagination_1xsiO>li>span:hover{border-top:1px solid transparent;border-bottom:1px solid transparent}.Pagination_pagination_1xsiO>li>span:focus,.Pagination_pagination_1xsiO>li>span:hover{background-color:#fff}.Pagination_info_2cUbo{float:right}.Pagination_info_2cUbo .Pagination_perPageSelector_CN8cp{margin-left:10px;margin-right:10px}.Server_table_1-Jbh{border-bottom:none}.Server_table_1-Jbh>thead:first-child>tr:first-child>th{border-top:1px solid #333;border-bottom:1px solid #333}.Server_table_1-Jbh>thead:first-child>tr:first-child>th a{cursor:default;color:inherit;text-decoration:none;display:block}.Server_table_1-Jbh>thead:first-child>tr:first-child>th.Server_sortable_351RP a{cursor:pointer}.Server_table_1-Jbh>thead:first-child>tr:first-child>th.Server_sortable_351RP a:focus{text-decoration:underline}.Server_table_1-Jbh>thead:first-child>tr:first-child>th.Server_sortable_351RP i{margin-top:5px;margin-left:5px}.Server_table_1-Jbh tbody>tr:first-child>th{background-color:#f2f2f2}.Server_table_1-Jbh tbody>tr:first-child>th a+span{margin-left:5px}.Server_table_1-Jbh tbody>tr:first-child>th a{color:#333;font-size:16px;display:inline-block;width:20px;text-align:center}.Server_table_1-Jbh .Server_checkbox_1lyNb{margin:0}.Server_table_1-Jbh .Server_checkbox_1lyNb label{min-height:18px}.Server_pagination_3erRE{margin:0}.Server_info_2gbZL{float:right}.Server_info_2gbZL .Server_perPageSelector_3GVN9{margin-left:10px;margin-right:10px}.Client_table_30YmA{border-bottom:none}.Client_table_30YmA>thead:first-child>tr:first-child>th{border-top:1px solid #333;border-bottom:1px solid #333}.Client_table_30YmA>thead:first-child>tr:first-child>th a{cursor:default;color:inherit;text-decoration:none;display:block}.Client_table_30YmA>thead:first-child>tr:first-child>th.Client_sortable_pJAaM a{cursor:pointer}.Client_table_30YmA>thead:first-child>tr:first-child>th.Client_sortable_pJAaM a:focus{text-decoration:underline}.Client_table_30YmA>thead:first-child>tr:first-child>th.Client_sortable_pJAaM i{margin-top:5px;margin-left:5px}.Client_table_30YmA tbody>tr:first-child>th{background-color:#f2f2f2}.Client_table_30YmA tbody>tr:first-child>th a+span{margin-left:5px}.Client_table_30YmA tbody>tr:first-child>th a{color:#333;font-size:16px;display:inline-block;width:20px;text-align:center}.Client_table_30YmA .Client_checkbox_2krmy{margin:0}.Client_table_30YmA .Client_checkbox_2krmy label{min-height:18px}td.Client_selectable_3NYta:hover{cursor:pointer}
--------------------------------------------------------------------------------
/src/components/mixins/default-props.js:
--------------------------------------------------------------------------------
1 | export default {
2 | /**
3 | * Key-value pairs with the headings to overwrite (label to display)
4 | * can also be overwritten with slot: "heading_colname"
5 | *
6 | * @inner
7 | * @type {Object}
8 | */
9 | headings: {},
10 | /**
11 | * Key-value pairs with templates (components) for the column value
12 | *
13 | * @type {Object}
14 | */
15 | templates: {},
16 | /**
17 | * empty object to disable sorting for all,
18 | * or define what columns are sortable; defaults to all sortable
19 | *
20 | * @default
21 | * @type {true|Object}
22 | */
23 | sortable: true,
24 | /**
25 | * Object (key, order) to sort table by on first load (on created)
26 | * @type {Object}
27 | */
28 | sortBy: {
29 | column: null,
30 | order: null,
31 | },
32 | /**
33 | * Required, unique identifier
34 | *
35 | * @default
36 | * @type {String}
37 | */
38 | uniqueKey: 'id',
39 | /**
40 | * show extra row for each row with details
41 | *
42 | * @default
43 | * @type {Boolean}
44 | */
45 | detailsRow: false,
46 | /**
47 | * number of items per page
48 | *
49 | * @default
50 | * @type {Number}
51 | */
52 | perPage: 10,
53 | /**
54 | * How many pages to show in the paginator. Odd number
55 | *
56 | * @default
57 | * @type {Number}
58 | */
59 | pageInterval: 7,
60 | /**
61 | * values to show in the selector of items per page
62 | *
63 | * @default
64 | * @type {Array}
65 | */
66 | perPageValues: [1, 2, 5, 10, 20, 50],
67 | /**
68 | * Classes to use on various elements
69 | *
70 | * @inner
71 | * @type {Object}
72 | */
73 | classes: {
74 | wrapper: 'table-responsive',
75 | table: 'table',
76 | sort: {
77 | none: 'fa fa-sort',
78 | ascending: 'fa fa-sort-asc',
79 | descending: 'fa fa-sort-desc',
80 | },
81 | checkbox: 'checkbox',
82 | pagination: {
83 | wrapper: 'pagination',
84 | formControl: 'form-control',
85 | info: 'info form-inline',
86 | first: 'fa fa-angle-double-left',
87 | prev: 'fa fa-angle-left',
88 | next: 'fa fa-angle-right',
89 | last: 'fa fa-angle-double-right',
90 | },
91 | group: {
92 | show: 'fa fa-chevron-right',
93 | hide: 'fa fa-chevron-down',
94 | },
95 | },
96 | /**
97 | * Texts
98 | *
99 | * @type Object
100 | */
101 | text: {
102 | /**
103 | * Text to show when row can be expanded
104 | * @type {String}
105 | */
106 | expand: 'Show details',
107 | /**
108 | * Text to show when row can be collapsed
109 | * @type {String}
110 | */
111 | collapse: 'Hide details',
112 | /**
113 | * Message to show when there is no data
114 | * @type {String}
115 | */
116 | noData: 'No data to show',
117 | /**
118 | * Message to show when no results are found for the search
119 | * @type {String}
120 | */
121 | emptyResults: 'No results for this filter',
122 | /**
123 | * Message to show when no results are found for the search
124 | * @type {String}
125 | */
126 | loading: 'Loading ...',
127 | /**
128 | * Text to show for pagination helper buttons
129 | * @type {Object}
130 | */
131 | pagination: {
132 | prev: '',
133 | next: '',
134 | info: {
135 | showing: 'Showing %s to %s of %s rows.',
136 | records: 'records per page',
137 | noRows: 'No rows to display',
138 | },
139 | },
140 | },
141 | /*
142 | * Key-value options for column and class
143 | */
144 | columnsClasses: {},
145 | /*
146 | * If to do inital fetch on create
147 | */
148 | initialFetch: true,
149 | /*
150 | * Key-value options for column and class
151 | */
152 | rowClasses: {},
153 | /**
154 | * Show the actions cell (with expand) last or first
155 | */
156 | actionsCellLast: true,
157 | };
158 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Countries of Europe
4 | ClientTable, which needs all data pre-loaded
5 |
6 |
7 |
Details for {{row.name}}.
8 |
Alpha2Code: {{row.cca2}}
9 |
Domain(s): {{row.tld.join(', ')}}
10 |
11 |
12 |
13 |
14 | All countries
15 | ServerTable, which loads data page by page
16 |
17 |
18 |
19 |
20 |
21 |
22 |
Details for {{row.name}}.
23 |
Alpha2Code: {{row.cca2}}
24 |
Domain(s): {{row.tld.join(', ')}}
25 |
26 |
27 |
28 |
29 |
30 |
157 |
158 |
167 |
--------------------------------------------------------------------------------
/tests/unit/Client.spec.js:
--------------------------------------------------------------------------------
1 | import { expect } from 'chai';
2 | import { shallowMount } from '@vue/test-utils';
3 | import Client from '@/components/Client.vue';
4 |
5 | describe('Client.vue', () => {
6 | it('Renders a table with 1 row', () => {
7 | const wrapper = shallowMount(Client, {
8 | propsData: {
9 | data: [{ first_name: '1', id: 1 }],
10 | },
11 | });
12 | expect(wrapper.contains('table tbody tr')).to.be.true;
13 |
14 | const rows = wrapper.findAll('table tbody tr');
15 | expect(rows).to.have.lengthOf(1);
16 | });
17 |
18 | it('Sort by columns', async () => {
19 | const wrapper = shallowMount(Client, {
20 | propsData: {
21 | data: [{
22 | first_name: '1',
23 | id: 1,
24 | eng: 10,
25 | }, {
26 | first_name: '2',
27 | id: 2,
28 | eng: 5,
29 | }, {
30 | first_name: '3',
31 | id: 3,
32 | eng: 15,
33 | }],
34 | columns: ['first_name', 'id'],
35 | },
36 | });
37 | expect(wrapper.contains('table tbody tr')).to.be.true;
38 | const rows = wrapper.findAll('table tbody tr');
39 | expect(rows).to.have.lengthOf(3);
40 |
41 | wrapper.vm.sortBy({
42 | key: 'id',
43 | order: 'descending',
44 | });
45 |
46 | expect(wrapper.vm.pageData).to.be.deep.equal({
47 | all: [{
48 | first_name: '3',
49 | id: 3,
50 | eng: 15,
51 | }, {
52 | first_name: '2',
53 | id: 2,
54 | eng: 5,
55 | }, {
56 | first_name: '1',
57 | id: 1,
58 | eng: 10,
59 | }],
60 | });
61 |
62 |
63 | wrapper.setProps({
64 | columns: ['first_name', 'id', 'eng'],
65 | });
66 | wrapper.vm.sortBy({
67 | key: 'eng',
68 | order: 'descending',
69 | });
70 | await wrapper.vm.$nextTick();
71 |
72 | expect(wrapper.vm.pageData).to.be.deep.equal({
73 | all: [{
74 | first_name: '3',
75 | id: 3,
76 | eng: 15,
77 | }, {
78 | first_name: '1',
79 | id: 1,
80 | eng: 10,
81 | }, {
82 | first_name: '2',
83 | id: 2,
84 | eng: 5,
85 | }],
86 | });
87 | });
88 |
89 | it('Adds row classes on ungrouped tables', () => {
90 | const wrapper = shallowMount(Client, {
91 | propsData: {
92 | data: [{
93 | first_name: '1',
94 | id: 1,
95 | testClass: true,
96 | }, {
97 | first_name: '2',
98 | id: 2,
99 | testClass: true,
100 | }, {
101 | first_name: '3',
102 | id: 3,
103 | testClass: false,
104 | }],
105 | options: {
106 | rowClasses: {
107 | testClass: 'testClass',
108 | },
109 | },
110 | },
111 | });
112 | expect(wrapper.contains('table tbody tr')).to.be.true;
113 |
114 | const rows = wrapper.findAll('table tbody tr.testClass');
115 | expect(rows).to.have.lengthOf(2);
116 | });
117 |
118 | it('Adds row classes on grouped tables', () => {
119 | const wrapper = shallowMount(Client, {
120 | propsData: {
121 | data: [{
122 | first_name: '1',
123 | id: 1,
124 | testClass: true,
125 | }, {
126 | first_name: '2',
127 | id: 2,
128 | testClass: false,
129 | }, {
130 | first_name: '2',
131 | id: 3,
132 | testClass: false,
133 | }, {
134 | first_name: '3',
135 | id: 4,
136 | testClass: true,
137 | }, {
138 | first_name: '3',
139 | id: 5,
140 | testClass: true,
141 | }],
142 | options: {
143 | groupBy: 'first_name',
144 | rowClasses: {
145 | testClass: 'testClass',
146 | },
147 | },
148 | },
149 | });
150 | expect(wrapper.contains('table tbody tr')).to.be.true;
151 |
152 | const rows = wrapper.findAll('table tbody tr.testClass');
153 | expect(rows).to.have.lengthOf(3);
154 | });
155 | });
156 |
157 | describe('Client.vue methods', () => {
158 | const wrapper = shallowMount(Client, {});
159 | it('prepareValueForCsv escapes quotes', () => {
160 | expect(wrapper.vm.prepareValueForCsv('test with quote "')).to.equal('"test with quote \\""');
161 | });
162 | it('prepareValueForCsv returns an empty string when input is null', () => {
163 | expect(wrapper.vm.prepareValueForCsv(null)).to.equal('');
164 | });
165 | it('prepareValueForCsv returns an empty string when input is undefined', () => {
166 | expect(wrapper.vm.prepareValueForCsv(undefined)).to.equal('');
167 | });
168 | it('prepareValueForCsv returns "0" when input is 0', () => {
169 | expect(wrapper.vm.prepareValueForCsv(0)).to.equal('"0"');
170 | });
171 | it('prepareValueForCsv removes line feeds', () => {
172 | expect(wrapper.vm.prepareValueForCsv('test with line feed \n')).to.equal('"test with line feed "');
173 | });
174 | it('prepareValueForCsv removes carriage returns', () => {
175 | expect(wrapper.vm.prepareValueForCsv('test with carriage return \r')).to.equal('"test with carriage return "');
176 | });
177 | it('getFileNameWithExtension returns a filename with .csv extension when input does not have it included', () => {
178 | expect(wrapper.vm.getFileNameWithExtension('filename')).to.equal('filename.csv');
179 | });
180 | });
181 |
--------------------------------------------------------------------------------
/src/components/mixins/Pagination.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
77 |
78 |
79 |
80 | {{text.info.showing | format(startRow+1, endRow, totalRows)}}
81 |
82 |
93 |
94 | {{text.info.records}}
95 |
96 |
97 |
98 |
99 | {{text.info.noRows}}
100 |
101 |
102 |
103 |
104 |
105 |
106 |
128 |
129 |
248 |
--------------------------------------------------------------------------------
/src/components/Server.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | |
12 |
21 |
22 |
23 | {{ key | heading(opts.headings) }}
24 |
25 |
26 |
31 |
32 |
33 | |
34 |
35 |
36 |
37 |
38 | |
39 |
40 | |
41 |
42 |
43 |
44 |
45 | |
46 |
47 | |
48 |
49 |
50 |
51 |
52 |
57 | |
59 |
60 |
62 |
63 |
64 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | {{entry[key]}}
79 |
80 | |
81 |
82 |
88 | |
89 |
90 |
91 | |
92 |
93 |
94 |
95 |
96 |
97 | |
98 |
109 | |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
173 |
174 |
403 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-table
2 |
3 | [](https://circleci.com/gh/myENA/vue-table)
4 | [](https://www.npmjs.com/package/@myena/vue-table)
5 | 
6 | [](https://www.npmjs.com/package/@myena/vue-table)
7 | 
8 | 
9 | 
10 |
11 |
12 | ## What's this
13 | Components to render a table using client or remote data
14 |
15 | ## Install
16 | ```
17 | npm install @myena/vue-table
18 | ```
19 |
20 | # Dependencies
21 |
22 | - Vue 2
23 | - Bootstrap 3
24 | - FontAwesome 4
25 |
26 | # Demo
27 | https://myena-vue-table.netlify.app/
28 |
29 | # Vue Client Table
30 |
31 | Vue component for rendering a client side table with pagination, grouping, sorting, filtering, details row.
32 | Entire table data should be given to the table and will be paginated client side. Data can come from a Vuex store.
33 |
34 | ## Usage:
35 |
36 | ```html
37 |
38 |
39 |
40 | (Total in group: {{data.total}})
41 |
42 |
43 | Custom heading of column1
44 |
45 |
46 | {{row.column1}}
47 |
48 |
49 | Div for details (expanded) row
50 |
51 |
52 | ```
53 |
54 | ### As plugin (or in Browser)
55 |
56 | ```javascript
57 | // this will create the global (window) object "EnaTableClient"
58 | import '@myena/vue-table/dist/EnaTableClient';
59 | // or include as script in html :
60 | // registers the component globally
61 |
62 | // in the view that contains the table
63 | const MyView = new Vue({
64 | data() {
65 | // Define properties
66 | return {
67 | /**
68 | * List of objects to present in the table
69 | *
70 | * @member
71 | * @type {Array}
72 | */
73 | data: Array,
74 | /**
75 | * List of keys to use from each object (table columns)
76 | *
77 | * @type {Array}
78 | */
79 | columns: Array,
80 | /**
81 | * The filter object. If updated will filter the results by the value
82 | *
83 | * @type {Object}
84 | */
85 | filter: {
86 | type: Object,
87 | default: () => ({
88 | // The search query string. If updated will filter the results by the value
89 | keyword: '',
90 | }),
91 | },
92 | /**
93 | * Loading indicator. If true, will display the `loadingMsg` instead of the body
94 | * @type {Boolean}
95 | */
96 | loading: {
97 | type: Boolean,
98 | default: false,
99 | },
100 | /**
101 | * Options for the table
102 | *
103 | * @inner
104 | * @type {Object}
105 | */
106 | options: {
107 | /**
108 | * Classes to use on various elements
109 | *
110 | * @inner
111 | * @type {Object}
112 | */
113 | classes: {
114 | wrapper: 'table-responsive',
115 | table: 'table',
116 | formControl: 'form-control',
117 | sort: {
118 | none: 'fa fa-sort',
119 | ascending: 'fa fa-sort-asc',
120 | descending: 'fa fa-sort-desc',
121 | },
122 | pagination: {
123 | wrapper: 'pagination',
124 | info: 'info form-inline',
125 | first: 'fa fa-angle-double-left',
126 | prev: 'fa fa-angle-left',
127 | next: 'fa fa-angle-right',
128 | last: 'fa fa-angle-double-right',
129 | },
130 | group: {
131 | show: 'fa fa-chevron-right',
132 | hide: 'fa fa-chevron-down',
133 | },
134 | },
135 | /**
136 | * Key-value pairs with the headings to overwrite (label to display)
137 | * can also be overwritten with slot: "heading_colname"
138 | *
139 | * @inner
140 | * @type {Object}
141 | */
142 | headings: {},
143 | /**
144 | * Key-value pairs with templates (components) for the column value
145 | *
146 | * @type {Object}
147 | */
148 | templates: {},
149 | /**
150 | * Key-value pairs with custom search function per column,
151 | * or false to disable search for that column
152 | *
153 | * @type {Object}
154 | */
155 | search: {},
156 | /**
157 | * Field to group by - key name
158 | *
159 | * @default
160 | * @type {Boolean|String}
161 | */
162 | groupBy: false,
163 | /**
164 | * Expand/collapse groups
165 | *
166 | * @default
167 | * @type {Boolean}
168 | */
169 | toggleGroups: false,
170 | /**
171 | * Object of data to use for each group "header" (key is the group value)
172 | *
173 | * @type {Object}
174 | */
175 | groupMeta: {},
176 | /**
177 | * Required, unique identifier
178 | *
179 | * @default
180 | * @type {String}
181 | */
182 | uniqueKey: 'id',
183 | /**
184 | * show extra row for each row with details
185 | *
186 | * @default
187 | * @type {Boolean}
188 | */
189 | detailsRow: false,
190 | /**
191 | * Texts
192 | *
193 | * @type Object
194 | */
195 | text: {
196 | /**
197 | * Text to show when row can be expanded
198 | * @type {String}
199 | */
200 | expand: 'Show details',
201 | /**
202 | * Text to show when row can be collapsed
203 | * @type {String}
204 | */
205 | collapse: 'Hide details',
206 | /**
207 | * Message to show when there is no data
208 | * @type {String}
209 | */
210 | noData: 'No data to show',
211 | /**
212 | * Message to show when no results are found for the search
213 | * @type {String}
214 | */
215 | emptyResults: 'No results for this filter',
216 | /**
217 | * Message to show when no results are found for the search
218 | * @type {String}
219 | */
220 | loading: 'Loading ...',
221 | /**
222 | * Text to show for pagination helper buttons
223 | * @type {Object}
224 | */
225 | pagination: {
226 | next: '',
227 | last: '',
228 | info: {
229 | showing: 'Showing %s to %s of %s rows.',
230 | records: 'records per page',
231 | noRows: 'No rows to display',
232 | },
233 | },
234 | },
235 | /**
236 | * empty object to disable sorting for all,
237 | * or define what columns are sortable; defaults to all sortable
238 | *
239 | * @default
240 | * @type {true|Object}
241 | */
242 | sortable: true,
243 | /**
244 | * false, to disable pagination - show all; defaults to true
245 | *
246 | * @default
247 | * @type {Boolean}
248 | */
249 | pagination: true,
250 | /**
251 | * number of items per page
252 | *
253 | * @default
254 | * @type {Number}
255 | */
256 | perPage: 10,
257 | /**
258 | * How many pages to show in the paginator. Odd number
259 | *
260 | * @default
261 | * @type {Number}
262 | */
263 | pageInterval: 7,
264 | /**
265 | * values to show in the selector of items per page
266 | *
267 | * @default
268 | * @type {Array}
269 | */
270 | perPageValues: [1, 2, 5, 10, 20, 50],
271 | /**
272 | * Is the table editable (eg: can select value)
273 | * @type {Boolean}
274 | */
275 | editable: false,
276 | /**
277 | * List of columns that should be disabled for click to select/deselect
278 | * @type {Array}
279 | */
280 | nonSelectableColumns: [],
281 | /**
282 | * Object (key, order) to sort table by on first load (on created)
283 | * @type {Object}
284 | */
285 | sortBy: {
286 | column: null,
287 | order: null,
288 | },
289 | /**
290 | * The collator used for sorting
291 | * @type {Intl.Collator}
292 | */
293 | sortCollator: new Intl.Collator('en', {
294 | numeric: true,
295 | sensitivity: 'base',
296 | }),
297 | },
298 | };
299 | },
300 | // OR use computed properties instead
301 | computed: {
302 | data() {
303 | return this.$store.state.myListData; // or any other source that has all data
304 | },
305 | },
306 | methods: {
307 | search(filter) {
308 | this.searchQuery = filter.keyword;
309 | },
310 | },
311 | watch: {
312 | data(data) {
313 | // set the group metas when data changes
314 | // groupColumn is the same as the one used for 'groupBy' option
315 | this.options.groupMeta = data.reduce((groupMeta, r) => {
316 | if (!groupMeta[r.groupColumn]) {
317 | groupMeta[r.groupColumn] = {
318 | label: r.groupColumn,
319 | total: 0,
320 | };
321 | }
322 | groupMeta[r.groupColumn].total += 1;
323 | return groupMeta;
324 | }, {});
325 | },
326 | },
327 | });
328 | ```
329 |
330 | ### As module/local component
331 |
332 | ```javascript
333 | import { Client } from '@myena/vue-table';
334 |
335 | // in the view that contains the table
336 | const MyView = new Vue({
337 | components: {
338 | ClientTable: Client,
339 | },
340 | data() {
341 | return {
342 | columns: ['column1', 'column2'],
343 | options: {
344 | },
345 | };
346 | },
347 | computed: {
348 | data() {
349 | return this.$store.state.myListData; // or any other source that has all data
350 | },
351 | },
352 | });
353 | ```
354 |
355 | # Vue Server Table
356 |
357 | Vue component for rendering a table that loads data from the server, with pagination, sorting, filtering, details row.
358 | It doesn't support grouping.
359 |
360 | ## Usage:
361 |
362 | ```html
363 |
364 |
365 |
366 |
367 |
368 |
369 | Custom heading of column1
370 |
371 |
372 | {{row.column1}}
373 |
374 |
375 | Div for details (expanded) row
376 |
377 |
378 | ```
379 |
380 | ```javascript
381 | import axios from 'axios';
382 | import Qs from 'qs';
383 | import { Server: ServerTable } from '@myena/vue-table';
384 |
385 | const myServerTable = {
386 | extends: ServerTable,
387 | methods: {
388 | /**
389 | * Override the fetch method
390 | */
391 | async fetch(params) {
392 | const { data } = await axios.get(this.url, {
393 | params: Object.assign({}, params, {
394 | filter: this.options.filter,
395 | }),
396 | paramsSerializer(p) {
397 | return Qs.stringify(p, { arrayFormat: 'brackets' });
398 | },
399 | });
400 | return data;
401 | },
402 | /**
403 | * Override the parse method to return `data` and `total` fields
404 | */
405 | parse({ list, total }) {
406 | return {
407 | data: list,
408 | total,
409 | };
410 | },
411 | },
412 | };
413 |
414 | export default {
415 | name: 'app',
416 | components: {
417 | ServerTable: myServerTable,
418 | },
419 | data: () => ({
420 | columns: ['name', 'capital', 'population'],
421 | url: 'https://us-central1-vue-myena-table.cloudfunctions.net/countries',
422 | options: {
423 | perPage: 5,
424 | uniqueKey: 'alpha3Code',
425 | // not handled by the component
426 | // added here for easier access in the overridden fetch function
427 | filter: {
428 | name: null,
429 | },
430 | },
431 | }),
432 | methods: {
433 | filter() {
434 | // call component loadData, which sets some params then calls fetch (above)
435 | this.$refs.serverTable.loadData();
436 | },
437 | },
438 | };
439 | ```
440 |
--------------------------------------------------------------------------------
/src/components/Client.vue:
--------------------------------------------------------------------------------
1 |
2 |
203 |
204 |
205 |
255 |
256 |
782 |
--------------------------------------------------------------------------------
/dist/EnaTableServer/EnaTableServer.umd.min.js:
--------------------------------------------------------------------------------
1 | (function(t,e){"object"===typeof exports&&"object"===typeof module?module.exports=e():"function"===typeof define&&define.amd?define([],e):"object"===typeof exports?exports["EnaTableServer"]=e():t["EnaTableServer"]=e()})("undefined"!==typeof self?self:this,(function(){return function(t){var e={};function n(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,r){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},n.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(r,o,function(e){return t[e]}.bind(null,o));return r},n.n=function(t){var e=t&&t.__esModule?function(){return t["default"]}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s="fb15")}({"00ee":function(t,e,n){var r=n("b622"),o=r("toStringTag"),i={};i[o]="z",t.exports="[object z]"===String(i)},"0366":function(t,e,n){var r=n("1c0b");t.exports=function(t,e,n){if(r(t),void 0===e)return t;switch(n){case 0:return function(){return t.call(e)};case 1:return function(n){return t.call(e,n)};case 2:return function(n,r){return t.call(e,n,r)};case 3:return function(n,r,o){return t.call(e,n,r,o)}}return function(){return t.apply(e,arguments)}}},"057f":function(t,e,n){var r=n("fc6a"),o=n("241c").f,i={}.toString,a="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],c=function(t){try{return o(t)}catch(e){return a.slice()}};t.exports.f=function(t){return a&&"[object Window]"==i.call(t)?c(t):o(r(t))}},"06cf":function(t,e,n){var r=n("83ab"),o=n("d1e7"),i=n("5c6c"),a=n("fc6a"),c=n("c04e"),s=n("5135"),u=n("0cfb"),f=Object.getOwnPropertyDescriptor;e.f=r?f:function(t,e){if(t=a(t),e=c(e,!0),u)try{return f(t,e)}catch(n){}if(s(t,e))return i(!o.f.call(t,e),t[e])}},"07ac":function(t,e,n){var r=n("23e7"),o=n("6f53").values;r({target:"Object",stat:!0},{values:function(t){return o(t)}})},"0a06":function(t,e,n){"use strict";var r=n("c532"),o=n("30b5"),i=n("f6b4"),a=n("5270"),c=n("4a7b"),s=n("848b"),u=s.validators;function f(t){this.defaults=t,this.interceptors={request:new i,response:new i}}f.prototype.request=function(t,e){"string"===typeof t?(e=e||{},e.url=t):e=t||{},e=c(this.defaults,e),e.method?e.method=e.method.toLowerCase():this.defaults.method?e.method=this.defaults.method.toLowerCase():e.method="get";var n=e.transitional;void 0!==n&&s.assertOptions(n,{silentJSONParsing:u.transitional(u.boolean),forcedJSONParsing:u.transitional(u.boolean),clarifyTimeoutError:u.transitional(u.boolean)},!1);var r=[],o=!0;this.interceptors.request.forEach((function(t){"function"===typeof t.runWhen&&!1===t.runWhen(e)||(o=o&&t.synchronous,r.unshift(t.fulfilled,t.rejected))}));var i,f=[];if(this.interceptors.response.forEach((function(t){f.push(t.fulfilled,t.rejected)})),!o){var l=[a,void 0];Array.prototype.unshift.apply(l,r),l=l.concat(f),i=Promise.resolve(e);while(l.length)i=i.then(l.shift(),l.shift());return i}var p=e;while(r.length){var d=r.shift(),h=r.shift();try{p=d(p)}catch(v){h(v);break}}try{i=a(p)}catch(v){return Promise.reject(v)}while(f.length)i=i.then(f.shift(),f.shift());return i},f.prototype.getUri=function(t){return t=c(this.defaults,t),o(t.url,t.params,t.paramsSerializer).replace(/^\?/,"")},r.forEach(["delete","get","head","options"],(function(t){f.prototype[t]=function(e,n){return this.request(c(n||{},{method:t,url:e,data:(n||{}).data}))}})),r.forEach(["post","put","patch"],(function(t){f.prototype[t]=function(e,n,r){return this.request(c(r||{},{method:t,url:e,data:n}))}})),t.exports=f},"0cfb":function(t,e,n){var r=n("83ab"),o=n("d039"),i=n("cc12");t.exports=!r&&!o((function(){return 7!=Object.defineProperty(i("div"),"a",{get:function(){return 7}}).a}))},"0df6":function(t,e,n){"use strict";t.exports=function(t){return function(e){return t.apply(null,e)}}},1276:function(t,e,n){"use strict";var r=n("d784"),o=n("44e7"),i=n("825a"),a=n("1d80"),c=n("4840"),s=n("8aa5"),u=n("50c4"),f=n("14c3"),l=n("9263"),p=n("d039"),d=[].push,h=Math.min,v=4294967295,g=!p((function(){return!RegExp(v,"y")}));r("split",2,(function(t,e,n){var r;return r="c"=="abbc".split(/(b)*/)[1]||4!="test".split(/(?:)/,-1).length||2!="ab".split(/(?:ab)*/).length||4!=".".split(/(.?)(.?)/).length||".".split(/()()/).length>1||"".split(/.?/).length?function(t,n){var r=String(a(this)),i=void 0===n?v:n>>>0;if(0===i)return[];if(void 0===t)return[r];if(!o(t))return e.call(r,t,i);var c,s,u,f=[],p=(t.ignoreCase?"i":"")+(t.multiline?"m":"")+(t.unicode?"u":"")+(t.sticky?"y":""),h=0,g=new RegExp(t.source,p+"g");while(c=l.call(g,r)){if(s=g.lastIndex,s>h&&(f.push(r.slice(h,c.index)),c.length>1&&c.index=i))break;g.lastIndex===c.index&&g.lastIndex++}return h===r.length?!u&&g.test("")||f.push(""):f.push(r.slice(h)),f.length>i?f.slice(0,i):f}:"0".split(void 0,0).length?function(t,n){return void 0===t&&0===n?[]:e.call(this,t,n)}:e,[function(e,n){var o=a(this),i=void 0==e?void 0:e[t];return void 0!==i?i.call(e,o,n):r.call(String(o),e,n)},function(t,o){var a=n(r,t,this,o,r!==e);if(a.done)return a.value;var l=i(t),p=String(this),d=c(l,RegExp),y=l.unicode,b=(l.ignoreCase?"i":"")+(l.multiline?"m":"")+(l.unicode?"u":"")+(g?"y":"g"),m=new d(g?l:"^(?:"+l.source+")",b),w=void 0===o?v:o>>>0;if(0===w)return[];if(0===p.length)return null===f(m,p)?[p]:[];var x=0,P=0,S=[];while(P1?arguments[1]:void 0)}})},"14c3":function(t,e,n){var r=n("c6b6"),o=n("9263");t.exports=function(t,e){var n=t.exec;if("function"===typeof n){var i=n.call(t,e);if("object"!==typeof i)throw TypeError("RegExp exec method returned something other than an Object or null");return i}if("RegExp"!==r(t))throw TypeError("RegExp#exec called on incompatible receiver");return o.call(t,e)}},"159b":function(t,e,n){var r=n("da84"),o=n("fdbc"),i=n("17c2"),a=n("9112");for(var c in o){var s=r[c],u=s&&s.prototype;if(u&&u.forEach!==i)try{a(u,"forEach",i)}catch(f){u.forEach=i}}},"17c2":function(t,e,n){"use strict";var r=n("b727").forEach,o=n("a640"),i=n("ae40"),a=o("forEach"),c=i("forEach");t.exports=a&&c?[].forEach:function(t){return r(this,t,arguments.length>1?arguments[1]:void 0)}},"19aa":function(t,e){t.exports=function(t,e,n){if(!(t instanceof e))throw TypeError("Incorrect "+(n?n+" ":"")+"invocation");return t}},"1be4":function(t,e,n){var r=n("d066");t.exports=r("document","documentElement")},"1c0b":function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},"1c7e":function(t,e,n){var r=n("b622"),o=r("iterator"),i=!1;try{var a=0,c={next:function(){return{done:!!a++}},return:function(){i=!0}};c[o]=function(){return this},Array.from(c,(function(){throw 2}))}catch(s){}t.exports=function(t,e){if(!e&&!i)return!1;var n=!1;try{var r={};r[o]=function(){return{next:function(){return{done:n=!0}}}},t(r)}catch(s){}return n}},"1cdc":function(t,e,n){var r=n("342f");t.exports=/(iphone|ipod|ipad).*applewebkit/i.test(r)},"1d2b":function(t,e,n){"use strict";t.exports=function(t,e){return function(){for(var n=new Array(arguments.length),r=0;r=51||!r((function(){var e=[],n=e.constructor={};return n[a]=function(){return{foo:1}},1!==e[t](Boolean).foo}))}},2266:function(t,e,n){var r=n("825a"),o=n("e95a"),i=n("50c4"),a=n("0366"),c=n("35a1"),s=n("9bdd"),u=function(t,e){this.stopped=t,this.result=e},f=t.exports=function(t,e,n,f,l){var p,d,h,v,g,y,b,m=a(e,n,f?2:1);if(l)p=t;else{if(d=c(t),"function"!=typeof d)throw TypeError("Target is not iterable");if(o(d)){for(h=0,v=i(t.length);v>h;h++)if(g=f?m(r(b=t[h])[0],b[1]):m(t[h]),g&&g instanceof u)return g;return new u(!1)}p=d.call(t)}y=p.next;while(!(b=y.call(p)).done)if(g=s(p,m,b.value,f),"object"==typeof g&&g&&g instanceof u)return g;return new u(!1)};f.stop=function(t){return new u(!0,t)}},"23cb":function(t,e,n){var r=n("a691"),o=Math.max,i=Math.min;t.exports=function(t,e){var n=r(t);return n<0?o(n+e,0):i(n,e)}},"23e7":function(t,e,n){var r=n("da84"),o=n("06cf").f,i=n("9112"),a=n("6eeb"),c=n("ce4e"),s=n("e893"),u=n("94ca");t.exports=function(t,e){var n,f,l,p,d,h,v=t.target,g=t.global,y=t.stat;if(f=g?r:y?r[v]||c(v,{}):(r[v]||{}).prototype,f)for(l in e){if(d=e[l],t.noTargetGet?(h=o(f,l),p=h&&h.value):p=f[l],n=u(g?l:v+(y?".":"#")+l,t.forced),!n&&void 0!==p){if(typeof d===typeof p)continue;s(d,p)}(t.sham||p&&p.sham)&&i(d,"sham",!0),a(f,l,d,t)}}},"241c":function(t,e,n){var r=n("ca84"),o=n("7839"),i=o.concat("length","prototype");e.f=Object.getOwnPropertyNames||function(t){return r(t,i)}},2532:function(t,e,n){"use strict";var r=n("23e7"),o=n("5a34"),i=n("1d80"),a=n("ab13");r({target:"String",proto:!0,forced:!a("includes")},{includes:function(t){return!!~String(i(this)).indexOf(o(t),arguments.length>1?arguments[1]:void 0)}})},2626:function(t,e,n){"use strict";var r=n("d066"),o=n("9bf2"),i=n("b622"),a=n("83ab"),c=i("species");t.exports=function(t){var e=r(t),n=o.f;a&&e&&!e[c]&&n(e,c,{configurable:!0,get:function(){return this}})}},"2cf4":function(t,e,n){var r,o,i,a=n("da84"),c=n("d039"),s=n("c6b6"),u=n("0366"),f=n("1be4"),l=n("cc12"),p=n("1cdc"),d=a.location,h=a.setImmediate,v=a.clearImmediate,g=a.process,y=a.MessageChannel,b=a.Dispatch,m=0,w={},x="onreadystatechange",P=function(t){if(w.hasOwnProperty(t)){var e=w[t];delete w[t],e()}},S=function(t){return function(){P(t)}},E=function(t){P(t.data)},O=function(t){a.postMessage(t+"",d.protocol+"//"+d.host)};h&&v||(h=function(t){var e=[],n=1;while(arguments.length>n)e.push(arguments[n++]);return w[++m]=function(){("function"==typeof t?t:Function(t)).apply(void 0,e)},r(m),m},v=function(t){delete w[t]},"process"==s(g)?r=function(t){g.nextTick(S(t))}:b&&b.now?r=function(t){b.now(S(t))}:y&&!p?(o=new y,i=o.port2,o.port1.onmessage=E,r=u(i.postMessage,i,1)):!a.addEventListener||"function"!=typeof postMessage||a.importScripts||c(O)||"file:"===d.protocol?r=x in l("script")?function(t){f.appendChild(l("script"))[x]=function(){f.removeChild(this),P(t)}}:function(t){setTimeout(S(t),0)}:(r=O,a.addEventListener("message",E,!1))),t.exports={set:h,clear:v}},"2d00":function(t,e,n){var r,o,i=n("da84"),a=n("342f"),c=i.process,s=c&&c.versions,u=s&&s.v8;u?(r=u.split("."),o=r[0]+r[1]):a&&(r=a.match(/Edge\/(\d+)/),(!r||r[1]>=74)&&(r=a.match(/Chrome\/(\d+)/),r&&(o=r[1]))),t.exports=o&&+o},"2d83":function(t,e,n){"use strict";var r=n("387f");t.exports=function(t,e,n,o,i){var a=new Error(t);return r(a,e,n,o,i)}},"2e67":function(t,e,n){"use strict";t.exports=function(t){return!(!t||!t.__CANCEL__)}},"2f27":function(t,e,n){"use strict";var r=n("378f"),o=n.n(r);e["default"]=o.a},"30b5":function(t,e,n){"use strict";var r=n("c532");function o(t){return encodeURIComponent(t).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}t.exports=function(t,e,n){if(!e)return t;var i;if(n)i=n(e);else if(r.isURLSearchParams(e))i=e.toString();else{var a=[];r.forEach(e,(function(t,e){null!==t&&"undefined"!==typeof t&&(r.isArray(t)?e+="[]":t=[t],r.forEach(t,(function(t){r.isDate(t)?t=t.toISOString():r.isObject(t)&&(t=JSON.stringify(t)),a.push(o(e)+"="+o(t))})))})),i=a.join("&")}if(i){var c=t.indexOf("#");-1!==c&&(t=t.slice(0,c)),t+=(-1===t.indexOf("?")?"?":"&")+i}return t}},"342f":function(t,e,n){var r=n("d066");t.exports=r("navigator","userAgent")||""},"35a1":function(t,e,n){var r=n("f5df"),o=n("3f8c"),i=n("b622"),a=i("iterator");t.exports=function(t){if(void 0!=t)return t[a]||t["@@iterator"]||o[r(t)]}},"378f":function(t,e,n){t.exports={pagination:"Pagination_pagination_1xsiO",info:"Pagination_info_2cUbo",perPageSelector:"Pagination_perPageSelector_CN8cp"}},"37e8":function(t,e,n){var r=n("83ab"),o=n("9bf2"),i=n("825a"),a=n("df75");t.exports=r?Object.defineProperties:function(t,e){i(t);var n,r=a(e),c=r.length,s=0;while(c>s)o.f(t,n=r[s++],e[n]);return t}},"387f":function(t,e,n){"use strict";t.exports=function(t,e,n,r,o){return t.config=e,n&&(t.code=n),t.request=r,t.response=o,t.isAxiosError=!0,t.toJSON=function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code,status:this.response&&this.response.status?this.response.status:null}},t}},3934:function(t,e,n){"use strict";var r=n("c532");t.exports=r.isStandardBrowserEnv()?function(){var t,e=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");function o(t){var r=t;return e&&(n.setAttribute("href",r),r=n.href),n.setAttribute("href",r),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:"/"===n.pathname.charAt(0)?n.pathname:"/"+n.pathname}}return t=o(window.location.href),function(e){var n=r.isString(e)?o(e):e;return n.protocol===t.protocol&&n.host===t.host}}():function(){return function(){return!0}}()},"3bbe":function(t,e,n){var r=n("861d");t.exports=function(t){if(!r(t)&&null!==t)throw TypeError("Can't set "+String(t)+" as a prototype");return t}},"3f8c":function(t,e){t.exports={}},4160:function(t,e,n){"use strict";var r=n("23e7"),o=n("17c2");r({target:"Array",proto:!0,forced:[].forEach!=o},{forEach:o})},"428f":function(t,e,n){var r=n("da84");t.exports=r},4362:function(t,e,n){e.nextTick=function(t){setTimeout(t,0)},e.platform=e.arch=e.execPath=e.title="browser",e.pid=1,e.browser=!0,e.env={},e.argv=[],e.binding=function(t){throw new Error("No such module. (Possibly not yet loaded)")},function(){var t,r="/";e.cwd=function(){return r},e.chdir=function(e){t||(t=n("df7c")),r=t.resolve(e,r)}}(),e.exit=e.kill=e.umask=e.dlopen=e.uptime=e.memoryUsage=e.uvCounters=function(){},e.features={}},"44ad":function(t,e,n){var r=n("d039"),o=n("c6b6"),i="".split;t.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?i.call(t,""):Object(t)}:Object},"44d2":function(t,e,n){var r=n("b622"),o=n("7c73"),i=n("9bf2"),a=r("unscopables"),c=Array.prototype;void 0==c[a]&&i.f(c,a,{configurable:!0,value:o(null)}),t.exports=function(t){c[a][t]=!0}},"44de":function(t,e,n){var r=n("da84");t.exports=function(t,e){var n=r.console;n&&n.error&&(1===arguments.length?n.error(t):n.error(t,e))}},"44e7":function(t,e,n){var r=n("861d"),o=n("c6b6"),i=n("b622"),a=i("match");t.exports=function(t){var e;return r(t)&&(void 0!==(e=t[a])?!!e:"RegExp"==o(t))}},"467f":function(t,e,n){"use strict";var r=n("2d83");t.exports=function(t,e,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?e(r("Request failed with status code "+n.status,n.config,null,n.request,n)):t(n)}},4840:function(t,e,n){var r=n("825a"),o=n("1c0b"),i=n("b622"),a=i("species");t.exports=function(t,e){var n,i=r(t).constructor;return void 0===i||void 0==(n=r(i)[a])?e:o(n)}},4930:function(t,e,n){var r=n("d039");t.exports=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())}))},"4a7b":function(t,e,n){"use strict";var r=n("c532");t.exports=function(t,e){e=e||{};var n={};function o(t,e){return r.isPlainObject(t)&&r.isPlainObject(e)?r.merge(t,e):r.isPlainObject(e)?r.merge({},e):r.isArray(e)?e.slice():e}function i(n){return r.isUndefined(e[n])?r.isUndefined(t[n])?void 0:o(void 0,t[n]):o(t[n],e[n])}function a(t){if(!r.isUndefined(e[t]))return o(void 0,e[t])}function c(n){return r.isUndefined(e[n])?r.isUndefined(t[n])?void 0:o(void 0,t[n]):o(void 0,e[n])}function s(n){return n in e?o(t[n],e[n]):n in t?o(void 0,t[n]):void 0}var u={url:a,method:a,data:a,baseURL:c,transformRequest:c,transformResponse:c,paramsSerializer:c,timeout:c,timeoutMessage:c,withCredentials:c,adapter:c,responseType:c,xsrfCookieName:c,xsrfHeaderName:c,onUploadProgress:c,onDownloadProgress:c,decompress:c,maxContentLength:c,maxBodyLength:c,transport:c,httpAgent:c,httpsAgent:c,cancelToken:c,socketPath:c,responseEncoding:c,validateStatus:s};return r.forEach(Object.keys(t).concat(Object.keys(e)),(function(t){var e=u[t]||i,o=e(t);r.isUndefined(o)&&e!==s||(n[t]=o)})),n}},"4c3d":function(t,e,n){"use strict";(function(e){var r=n("c532"),o=n("c8af"),i=n("387f"),a=n("cafa"),c={"Content-Type":"application/x-www-form-urlencoded"};function s(t,e){!r.isUndefined(t)&&r.isUndefined(t["Content-Type"])&&(t["Content-Type"]=e)}function u(){var t;return("undefined"!==typeof XMLHttpRequest||"undefined"!==typeof e&&"[object process]"===Object.prototype.toString.call(e))&&(t=n("b50d")),t}function f(t,e,n){if(r.isString(t))try{return(e||JSON.parse)(t),r.trim(t)}catch(o){if("SyntaxError"!==o.name)throw o}return(n||JSON.stringify)(t)}var l={transitional:a,adapter:u(),transformRequest:[function(t,e){return o(e,"Accept"),o(e,"Content-Type"),r.isFormData(t)||r.isArrayBuffer(t)||r.isBuffer(t)||r.isStream(t)||r.isFile(t)||r.isBlob(t)?t:r.isArrayBufferView(t)?t.buffer:r.isURLSearchParams(t)?(s(e,"application/x-www-form-urlencoded;charset=utf-8"),t.toString()):r.isObject(t)||e&&"application/json"===e["Content-Type"]?(s(e,"application/json"),f(t)):t}],transformResponse:[function(t){var e=this.transitional||l.transitional,n=e&&e.silentJSONParsing,o=e&&e.forcedJSONParsing,a=!n&&"json"===this.responseType;if(a||o&&r.isString(t)&&t.length)try{return JSON.parse(t)}catch(c){if(a){if("SyntaxError"===c.name)throw i(c,this,"E_JSON_PARSE");throw c}}return t}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,validateStatus:function(t){return t>=200&&t<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],(function(t){l.headers[t]={}})),r.forEach(["post","put","patch"],(function(t){l.headers[t]=r.merge(c)})),t.exports=l}).call(this,n("4362"))},"4c67":function(t,e,n){"use strict";var r=n("dd1a"),o=n.n(r);e["default"]=o.a},"4d64":function(t,e,n){var r=n("fc6a"),o=n("50c4"),i=n("23cb"),a=function(t){return function(e,n,a){var c,s=r(e),u=o(s.length),f=i(a,u);if(t&&n!=n){while(u>f)if(c=s[f++],c!=c)return!0}else for(;u>f;f++)if((t||f in s)&&s[f]===n)return t||f||0;return!t&&-1}};t.exports={includes:a(!0),indexOf:a(!1)}},"4de4":function(t,e,n){"use strict";var r=n("23e7"),o=n("b727").filter,i=n("1dde"),a=n("ae40"),c=i("filter"),s=a("filter");r({target:"Array",proto:!0,forced:!c||!s},{filter:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},"50c4":function(t,e,n){var r=n("a691"),o=Math.min;t.exports=function(t){return t>0?o(r(t),9007199254740991):0}},5135:function(t,e){var n={}.hasOwnProperty;t.exports=function(t,e){return n.call(t,e)}},5270:function(t,e,n){"use strict";var r=n("c532"),o=n("c401"),i=n("2e67"),a=n("4c3d"),c=n("7a77");function s(t){if(t.cancelToken&&t.cancelToken.throwIfRequested(),t.signal&&t.signal.aborted)throw new c("canceled")}t.exports=function(t){s(t),t.headers=t.headers||{},t.data=o.call(t,t.data,t.headers,t.transformRequest),t.headers=r.merge(t.headers.common||{},t.headers[t.method]||{},t.headers),r.forEach(["delete","get","head","post","put","patch","common"],(function(e){delete t.headers[e]}));var e=t.adapter||a.adapter;return e(t).then((function(e){return s(t),e.data=o.call(t,e.data,e.headers,t.transformResponse),e}),(function(e){return i(e)||(s(t),e&&e.response&&(e.response.data=o.call(t,e.response.data,e.response.headers,t.transformResponse))),Promise.reject(e)}))}},5319:function(t,e,n){"use strict";var r=n("d784"),o=n("825a"),i=n("7b0b"),a=n("50c4"),c=n("a691"),s=n("1d80"),u=n("8aa5"),f=n("14c3"),l=Math.max,p=Math.min,d=Math.floor,h=/\$([$&'`]|\d\d?|<[^>]*>)/g,v=/\$([$&'`]|\d\d?)/g,g=function(t){return void 0===t?t:String(t)};r("replace",2,(function(t,e,n,r){var y=r.REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE,b=r.REPLACE_KEEPS_$0,m=y?"$":"$0";return[function(n,r){var o=s(this),i=void 0==n?void 0:n[t];return void 0!==i?i.call(n,o,r):e.call(String(o),n,r)},function(t,r){if(!y&&b||"string"===typeof r&&-1===r.indexOf(m)){var i=n(e,t,this,r);if(i.done)return i.value}var s=o(t),d=String(this),h="function"===typeof r;h||(r=String(r));var v=s.global;if(v){var x=s.unicode;s.lastIndex=0}var P=[];while(1){var S=f(s,d);if(null===S)break;if(P.push(S),!v)break;var E=String(S[0]);""===E&&(s.lastIndex=u(d,a(s.lastIndex),x))}for(var O="",_=0,j=0;j=_&&(O+=d.slice(_,R)+N,_=R+T.length)}return O+d.slice(_)}];function w(t,n,r,o,a,c){var s=r+t.length,u=o.length,f=v;return void 0!==a&&(a=i(a),f=h),e.call(c,f,(function(e,i){var c;switch(i.charAt(0)){case"$":return"$";case"&":return t;case"`":return n.slice(0,r);case"'":return n.slice(s);case"<":c=a[i.slice(1,-1)];break;default:var f=+i;if(0===f)return e;if(f>u){var l=d(f/10);return 0===l?e:l<=u?void 0===o[l-1]?i.charAt(1):o[l-1]+i.charAt(1):e}c=o[f-1]}return void 0===c?"":c}))}}))},5692:function(t,e,n){var r=n("c430"),o=n("c6cd");(t.exports=function(t,e){return o[t]||(o[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.5",mode:r?"pure":"global",copyright:"© 2020 Denis Pushkarev (zloirock.ru)"})},"56ef":function(t,e,n){var r=n("d066"),o=n("241c"),i=n("7418"),a=n("825a");t.exports=r("Reflect","ownKeys")||function(t){var e=o.f(a(t)),n=i.f;return n?e.concat(n(t)):e}},5899:function(t,e){t.exports="\t\n\v\f\r \u2028\u2029\ufeff"},"58a8":function(t,e,n){var r=n("1d80"),o=n("5899"),i="["+o+"]",a=RegExp("^"+i+i+"*"),c=RegExp(i+i+"*$"),s=function(t){return function(e){var n=String(r(e));return 1&t&&(n=n.replace(a,"")),2&t&&(n=n.replace(c,"")),n}};t.exports={start:s(1),end:s(2),trim:s(3)}},"5a34":function(t,e,n){var r=n("44e7");t.exports=function(t){if(r(t))throw TypeError("The method doesn't accept regular expressions");return t}},"5c6c":function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},"5cce":function(t,e){t.exports={version:"0.26.1"}},"5f02":function(t,e,n){"use strict";var r=n("c532");t.exports=function(t){return r.isObject(t)&&!0===t.isAxiosError}},"60da":function(t,e,n){"use strict";var r=n("83ab"),o=n("d039"),i=n("df75"),a=n("7418"),c=n("d1e7"),s=n("7b0b"),u=n("44ad"),f=Object.assign,l=Object.defineProperty;t.exports=!f||o((function(){if(r&&1!==f({b:1},f(l({},"a",{enumerable:!0,get:function(){l(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},n=Symbol(),o="abcdefghijklmnopqrst";return t[n]=7,o.split("").forEach((function(t){e[t]=t})),7!=f({},t)[n]||i(f({},e)).join("")!=o}))?function(t,e){var n=s(t),o=arguments.length,f=1,l=a.f,p=c.f;while(o>f){var d,h=u(arguments[f++]),v=l?i(h).concat(l(h)):i(h),g=v.length,y=0;while(g>y)d=v[y++],r&&!p.call(h,d)||(n[d]=h[d])}return n}:f},6547:function(t,e,n){var r=n("a691"),o=n("1d80"),i=function(t){return function(e,n){var i,a,c=String(o(e)),s=r(n),u=c.length;return s<0||s>=u?t?"":void 0:(i=c.charCodeAt(s),i<55296||i>56319||s+1===u||(a=c.charCodeAt(s+1))<56320||a>57343?t?c.charAt(s):i:t?c.slice(s,s+2):a-56320+(i-55296<<10)+65536)}};t.exports={codeAt:i(!1),charAt:i(!0)}},"65f0":function(t,e,n){var r=n("861d"),o=n("e8b5"),i=n("b622"),a=i("species");t.exports=function(t,e){var n;return o(t)&&(n=t.constructor,"function"!=typeof n||n!==Array&&!o(n.prototype)?r(n)&&(n=n[a],null===n&&(n=void 0)):n=void 0),new(void 0===n?Array:n)(0===e?0:e)}},"69f3":function(t,e,n){var r,o,i,a=n("7f9a"),c=n("da84"),s=n("861d"),u=n("9112"),f=n("5135"),l=n("f772"),p=n("d012"),d=c.WeakMap,h=function(t){return i(t)?o(t):r(t,{})},v=function(t){return function(e){var n;if(!s(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}};if(a){var g=new d,y=g.get,b=g.has,m=g.set;r=function(t,e){return m.call(g,t,e),e},o=function(t){return y.call(g,t)||{}},i=function(t){return b.call(g,t)}}else{var w=l("state");p[w]=!0,r=function(t,e){return u(t,w,e),e},o=function(t){return f(t,w)?t[w]:{}},i=function(t){return f(t,w)}}t.exports={set:r,get:o,has:i,enforce:h,getterFor:v}},"6eeb":function(t,e,n){var r=n("da84"),o=n("9112"),i=n("5135"),a=n("ce4e"),c=n("8925"),s=n("69f3"),u=s.get,f=s.enforce,l=String(String).split("String");(t.exports=function(t,e,n,c){var s=!!c&&!!c.unsafe,u=!!c&&!!c.enumerable,p=!!c&&!!c.noTargetGet;"function"==typeof n&&("string"!=typeof e||i(n,"name")||o(n,"name",e),f(n).source=l.join("string"==typeof e?e:"")),t!==r?(s?!p&&t[e]&&(u=!0):delete t[e],u?t[e]=n:o(t,e,n)):u?t[e]=n:a(e,n)})(Function.prototype,"toString",(function(){return"function"==typeof this&&u(this).source||c(this)}))},"6f53":function(t,e,n){var r=n("83ab"),o=n("df75"),i=n("fc6a"),a=n("d1e7").f,c=function(t){return function(e){var n,c=i(e),s=o(c),u=s.length,f=0,l=[];while(u>f)n=s[f++],r&&!a.call(c,n)||l.push(t?[n,c[n]]:c[n]);return l}};t.exports={entries:c(!0),values:c(!1)}},7156:function(t,e,n){var r=n("861d"),o=n("d2bb");t.exports=function(t,e,n){var i,a;return o&&"function"==typeof(i=e.constructor)&&i!==n&&r(a=i.prototype)&&a!==n.prototype&&o(t,a),t}},7418:function(t,e){e.f=Object.getOwnPropertySymbols},"746f":function(t,e,n){var r=n("428f"),o=n("5135"),i=n("e538"),a=n("9bf2").f;t.exports=function(t){var e=r.Symbol||(r.Symbol={});o(e,t)||a(e,t,{value:i.f(t)})}},7839:function(t,e){t.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},"7a77":function(t,e,n){"use strict";function r(t){this.message=t}r.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},r.prototype.__CANCEL__=!0,t.exports=r},"7aac":function(t,e,n){"use strict";var r=n("c532");t.exports=r.isStandardBrowserEnv()?function(){return{write:function(t,e,n,o,i,a){var c=[];c.push(t+"="+encodeURIComponent(e)),r.isNumber(n)&&c.push("expires="+new Date(n).toGMTString()),r.isString(o)&&c.push("path="+o),r.isString(i)&&c.push("domain="+i),!0===a&&c.push("secure"),document.cookie=c.join("; ")},read:function(t){var e=document.cookie.match(new RegExp("(^|;\\s*)("+t+")=([^;]*)"));return e?decodeURIComponent(e[3]):null},remove:function(t){this.write(t,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},"7b0b":function(t,e,n){var r=n("1d80");t.exports=function(t){return Object(r(t))}},"7c73":function(t,e,n){var r,o=n("825a"),i=n("37e8"),a=n("7839"),c=n("d012"),s=n("1be4"),u=n("cc12"),f=n("f772"),l=">",p="<",d="prototype",h="script",v=f("IE_PROTO"),g=function(){},y=function(t){return p+h+l+t+p+"/"+h+l},b=function(t){t.write(y("")),t.close();var e=t.parentWindow.Object;return t=null,e},m=function(){var t,e=u("iframe"),n="java"+h+":";return e.style.display="none",s.appendChild(e),e.src=String(n),t=e.contentWindow.document,t.open(),t.write(y("document.F=Object")),t.close(),t.F},w=function(){try{r=document.domain&&new ActiveXObject("htmlfile")}catch(e){}w=r?b(r):m();var t=a.length;while(t--)delete w[d][a[t]];return w()};c[v]=!0,t.exports=Object.create||function(t,e){var n;return null!==t?(g[d]=o(t),n=new g,g[d]=null,n[v]=t):n=w(),void 0===e?n:i(n,e)}},"7f9a":function(t,e,n){var r=n("da84"),o=n("8925"),i=r.WeakMap;t.exports="function"===typeof i&&/native code/.test(o(i))},"825a":function(t,e,n){var r=n("861d");t.exports=function(t){if(!r(t))throw TypeError(String(t)+" is not an object");return t}},"83ab":function(t,e,n){var r=n("d039");t.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},"83b9":function(t,e,n){"use strict";var r=n("d925"),o=n("e683");t.exports=function(t,e){return t&&!r(e)?o(t,e):e}},8418:function(t,e,n){"use strict";var r=n("c04e"),o=n("9bf2"),i=n("5c6c");t.exports=function(t,e,n){var a=r(e);a in t?o.f(t,a,i(0,n)):t[a]=n}},"848b":function(t,e,n){"use strict";var r=n("5cce").version,o={};["object","boolean","number","function","string","symbol"].forEach((function(t,e){o[t]=function(n){return typeof n===t||"a"+(e<1?"n ":" ")+t}}));var i={};function a(t,e,n){if("object"!==typeof t)throw new TypeError("options must be an object");var r=Object.keys(t),o=r.length;while(o-- >0){var i=r[o],a=e[i];if(a){var c=t[i],s=void 0===c||a(c,i,t);if(!0!==s)throw new TypeError("option "+i+" must be "+s)}else if(!0!==n)throw Error("Unknown option "+i)}}o.transitional=function(t,e,n){function o(t,e){return"[Axios v"+r+"] Transitional option '"+t+"'"+e+(n?". "+n:"")}return function(n,r,a){if(!1===t)throw new Error(o(r," has been removed"+(e?" in "+e:"")));return e&&!i[r]&&(i[r]=!0,console.warn(o(r," has been deprecated since v"+e+" and will be removed in the near future"))),!t||t(n,r,a)}},t.exports={assertOptions:a,validators:o}},"861d":function(t,e){t.exports=function(t){return"object"===typeof t?null!==t:"function"===typeof t}},8875:function(t,e,n){var r,o,i;(function(n,a){o=[],r=a,i="function"===typeof r?r.apply(e,o):r,void 0===i||(t.exports=i)})("undefined"!==typeof self&&self,(function(){function t(){if(document.currentScript)return document.currentScript;try{throw new Error}catch(l){var t,e,n,r=/.*at [^(]*\((.*):(.+):(.+)\)$/gi,o=/@([^@]*):(\d+):(\d+)\s*$/gi,i=r.exec(l.stack)||o.exec(l.stack),a=i&&i[1]||!1,c=i&&i[2]||!1,s=document.location.href.replace(document.location.hash,""),u=document.getElementsByTagName("script");a===s&&(t=document.documentElement.outerHTML,e=new RegExp("(?:[^\\n]+?\\n){0,"+(c-2)+"}[^<]*