├── static
└── .gitkeep
├── npm-debug.log.3836475044
├── .eslintignore
├── config
├── prod.env.js
├── dev.env.js
└── index.js
├── .gitignore
├── src
├── assets
│ └── logo.png
├── helpers
│ └── event-bus.js
├── main.js
├── mixins
│ ├── Requests.js
│ ├── Pagination.js
│ └── Validator.js
├── App.vue
└── components
│ └── VueEditortable.vue
├── .editorconfig
├── .postcssrc.js
├── index.html
├── .babelrc
├── .eslintrc.js
├── LICENSE
├── package.json
└── README.md
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/npm-debug.log.3836475044:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | config/*.js
3 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log
5 | json/
6 | notes.txt
7 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/el-jacko/vue-editortable/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/src/helpers/event-bus.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 |
3 | const VetEventBus = new Vue();
4 |
5 | export default VetEventBus;
6 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | // to edit target browsers: use "browserlist" field in package.json
6 | "autoprefixer": {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | vue-editortable
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", { "modules": false }],
4 | "stage-2"
5 | ],
6 | "plugins": ["transform-runtime"],
7 | "comments": false,
8 | "env": {
9 | "test": {
10 | "presets": ["env", "stage-2"],
11 | "plugins": [ "istanbul" ]
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue';
4 | import Vuetify from 'vuetify';
5 | import App from './App';
6 |
7 | Vue.use(Vuetify);
8 |
9 | /* eslint-disable no-new */
10 | new Vue({
11 | el: '#app',
12 | template: '',
13 | components: { App },
14 | });
15 |
--------------------------------------------------------------------------------
/src/mixins/Requests.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | export default {
4 | methods: {
5 | getData(url, cb, errorCb) {
6 | axios.get(url).then(cb).catch(errorCb);
7 | },
8 | postData(url, data, cb, errorCb) {
9 | axios.post(url, data).then(cb).catch(errorCb);
10 | },
11 | putData(url, data, cb, errorCb) {
12 | axios.put(url, data).then(cb).catch(errorCb);
13 | },
14 | patchData(url, data, cb, errorCb) {
15 | axios.patch(url, data).then(cb).catch(errorCb);
16 | },
17 | deleteData(url, cb, errorCb) {
18 | axios.delete(url).then(cb).catch(errorCb);
19 | },
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // http://eslint.org/docs/user-guide/configuring
2 |
3 | module.exports = {
4 | root: true,
5 | parser: 'babel-eslint',
6 | parserOptions: {
7 | sourceType: 'module'
8 | },
9 | env: {
10 | browser: true,
11 | },
12 | extends: 'airbnb-base',
13 | // required to lint *.vue files
14 | plugins: [
15 | 'html'
16 | ],
17 | // check if imports actually resolve
18 | 'settings': {
19 | 'import/resolver': {
20 | 'webpack': {
21 | 'config': 'build/webpack.base.conf.js'
22 | }
23 | }
24 | },
25 | // add your custom rules here
26 | 'rules': {
27 | 'no-console': 0,
28 | // don't require .vue extension when importing
29 | 'import/extensions': ['error', 'always', {
30 | 'js': 'never',
31 | 'vue': 'never'
32 | }],
33 | // allow optionalDependencies
34 | 'import/no-extraneous-dependencies': ['error', {
35 | 'optionalDependencies': ['test/unit/index.js']
36 | }],
37 | // allow debugger during development
38 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Jacques Mannon
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 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'static',
10 | assetsPublicPath: '/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css'],
18 | // Run the build command with an extra argument to
19 | // View the bundle analyzer report after build finishes:
20 | // `npm run build --report`
21 | // Set to `true` or `false` to always turn it on or off
22 | bundleAnalyzerReport: process.env.npm_config_report
23 | },
24 | dev: {
25 | env: require('./dev.env'),
26 | port: 8080,
27 | autoOpenBrowser: true,
28 | assetsSubDirectory: 'static',
29 | assetsPublicPath: '/',
30 | proxyTable: {},
31 | // CSS Sourcemaps off by default because relative paths are "buggy"
32 | // with this option, according to the CSS-Loader README
33 | // (https://github.com/webpack/css-loader#sourcemaps)
34 | // In our experience, they generally work as expected,
35 | // just be aware of this issue when enabling this option.
36 | cssSourceMap: false
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/mixins/Pagination.js:
--------------------------------------------------------------------------------
1 | export default {
2 | data() {
3 | return {
4 | currentPage: 0,
5 | maxNumber: 0,
6 | resultCount: 0,
7 | };
8 | },
9 | methods: {
10 | setPage(pageNumber) {
11 | this.currentPage = pageNumber - 1;
12 | },
13 | resetCurrentPage() {
14 | this.currentPage = 0;
15 | },
16 | showPrev() {
17 | if (this.isStartPage) return;
18 | this.currentPage -= 1;
19 | },
20 | showNext() {
21 | if (this.isEndPage) return;
22 | this.currentPage += 1;
23 | },
24 | paginate(data) {
25 | this.resultCount = data.length;
26 | this.maxNumber = this.totalPages - 1;
27 | const index = this.currentPage * this.opt.pagination.itemsPerPage;
28 | return data.slice(index, index + this.opt.pagination.itemsPerPage);
29 | },
30 | isInPaginationRange(pageNumber) {
31 | let show;
32 | if (
33 | this.maxNumber < 7 ||
34 | pageNumber === 1 ||
35 | pageNumber >= this.maxNumber + 1 ||
36 | (pageNumber <= 5 && this.currentPage < 3) ||
37 | (pageNumber >= this.maxNumber - 3 && this.currentPage > this.maxNumber - 4) ||
38 | (pageNumber >= this.currentPage && pageNumber <= (this.currentPage + 2))
39 | ) {
40 | show = true;
41 | }
42 | return show;
43 | },
44 | },
45 | computed: {
46 | totalPages() {
47 | return Math.ceil(this.resultCount / this.opt.pagination.itemsPerPage);
48 | },
49 | isStartPage() {
50 | return (this.currentPage === 0);
51 | },
52 | isEndPage() {
53 | return (this.currentPage + 1) *
54 | this.opt.pagination.itemsPerPage >= this.resultCount;
55 | },
56 | },
57 | };
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-editortable",
3 | "version": "1.1.5",
4 | "description": "A Vue.js editable table component",
5 | "author": "Jacques Mannon",
6 | "private": false,
7 | "main": "./src/components/VueEditortable.vue",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/el-jacko/vue-editortable.git"
11 | },
12 | "license": "MIT",
13 | "scripts": {
14 | "dev": "node build/dev-server.js",
15 | "build": "node build/build.js",
16 | "lint": "eslint --ext .js,.vue src"
17 | },
18 | "dependencies": {
19 | "axios": "^0.16.1",
20 | "validator": "^7.0.0",
21 | "vue": "^2.2.2",
22 | "vue-awesome": "^2.1.0",
23 | "vue-resource": "^1.2.1"
24 | },
25 | "devDependencies": {
26 | "autoprefixer": "^6.7.2",
27 | "babel-core": "^6.22.1",
28 | "babel-eslint": "^7.1.1",
29 | "babel-loader": "^6.2.10",
30 | "babel-plugin-transform-runtime": "^6.22.0",
31 | "babel-preset-env": "^1.2.1",
32 | "babel-preset-stage-2": "^6.22.0",
33 | "babel-register": "^6.22.0",
34 | "chalk": "^1.1.3",
35 | "connect-history-api-fallback": "^1.3.0",
36 | "copy-webpack-plugin": "^4.0.1",
37 | "css-loader": "^0.26.1",
38 | "eslint": "^3.14.1",
39 | "eslint-config-airbnb-base": "^11.0.1",
40 | "eslint-friendly-formatter": "^2.0.7",
41 | "eslint-import-resolver-webpack": "^0.8.1",
42 | "eslint-loader": "^1.6.1",
43 | "eslint-plugin-html": "^2.0.0",
44 | "eslint-plugin-import": "^2.2.0",
45 | "eventsource-polyfill": "^0.9.6",
46 | "express": "^4.14.1",
47 | "extract-text-webpack-plugin": "^2.0.0",
48 | "file-loader": "^0.10.0",
49 | "friendly-errors-webpack-plugin": "^1.1.3",
50 | "function-bind": "^1.1.0",
51 | "html-webpack-plugin": "^2.28.0",
52 | "http-proxy-middleware": "^0.17.3",
53 | "opn": "^4.0.2",
54 | "optimize-css-assets-webpack-plugin": "^1.3.0",
55 | "ora": "^1.1.0",
56 | "rimraf": "^2.6.0",
57 | "semver": "^5.3.0",
58 | "url-loader": "^0.5.7",
59 | "vue-loader": "^11.1.4",
60 | "vue-style-loader": "^2.0.0",
61 | "vue-template-compiler": "^2.2.1",
62 | "vuetify": "^0.12.7",
63 | "webpack": "^2.2.1",
64 | "webpack-bundle-analyzer": "^2.2.1",
65 | "webpack-dev-middleware": "^1.10.0",
66 | "webpack-hot-middleware": "^2.16.1",
67 | "webpack-merge": "^2.6.1"
68 | },
69 | "engines": {
70 | "node": ">= 4.0.0",
71 | "npm": ">= 3.0.0"
72 | },
73 | "browserslist": [
74 | "> 1%",
75 | "last 2 versions",
76 | "not ie <= 8"
77 | ]
78 | }
79 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
115 |
116 |
123 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Important
2 | Due to lack of time this project is on hold.
3 |
4 | ## Support on Beerpay
5 | Hey dude! Help me out for a couple of :beers:!
6 |
7 | [](https://beerpay.io/el-jacko/vue-editortable) [](https://beerpay.io/el-jacko/vue-editortable?focus=wish)
8 |
9 | # vue-editortable
10 |
11 | > A Vue.js editable table component
12 | > * Load/Save Data from/to a database
13 | > * Create, Edit, Save, and Delete Data
14 | > * Show/Hide columns
15 | > * Keyboard Navigation & Shortcuts
16 | > * SWIPE Design for wide tables
17 | > * Simple Responsive Design with data attributes
18 | > * Configurable
19 | > * Multisorting
20 | > * Searchfilter
21 | > * dynamic Pagination
22 | > * Validation
23 |
24 | ---
25 | ## Demo
26 | * Demo Pages are temporarely offline
27 |
28 | ---
29 | ## Dependencies
30 |
31 | Only Vue.js, no other frameworks/libraries
32 | * Vue.js >= 2.0 (tested with 2.2.2)
33 | * Vue-awesome Icons
34 | * Axios
35 | * validator
36 |
37 | ---
38 | ## Browser compatibility
39 |
40 | Only tested browser by now is Chrome.
41 | Feel free to test and share your results.
42 |
43 | ---
44 | ## Installation
45 |
46 | #### If you use Webpack/Browserify
47 |
48 | ### npm
49 | ``` sh
50 | npm install --save vue-editortable
51 | ```
52 | Import globally in an App:
53 |
54 | ``` javascript
55 | import VueEditortable from "vue-editortable"
56 | Vue.component('vue-editortable', VueEditortable)
57 | ```
58 | Import locally in a component:
59 |
60 | ``` javascript
61 | import VueEditortable from "vue-editortable"
62 | // ...
63 | components: {
64 | VueEditortable,
65 | }
66 | // ...
67 | ```
68 |
69 | ## Usage
70 |
71 | ``` html
72 |
73 | ```
74 | ``` javascript
75 | // ...
76 | data() {
77 | return {
78 | columns: [
79 | {
80 | title: 'Id',
81 | name: 'id',
82 | editable: false,
83 | },
84 | {
85 | title: 'Firstname',
86 | name: 'firstname',
87 | editable: true,
88 | },
89 | {
90 | title: 'Lastname',
91 | name: 'lastname',
92 | editable: true,
93 | },
94 | {
95 | title: 'Email',
96 | name: 'email',
97 | editable: true,
98 | },
99 | ],
100 | options: {
101 | showSearchFilter: true,
102 | requests: {
103 | allUrl: 'http://api.dev/api/users',
104 | },
105 | },
106 | };
107 | },
108 | // ...
109 | ```
110 |
111 | ---
112 | ## Documentation
113 |
114 | You will find a complete documentation [here](https://github.com/el-jacko/vue-editortable/wiki).
115 |
116 | ---
117 | ## Build Setup
118 |
119 | ``` sh
120 | # install dependencies
121 | npm install
122 |
123 | # serve with hot reload at localhost:8080
124 | npm run dev
125 |
126 | # build for production with minification
127 | npm run build
128 |
129 | # build for production and view the bundle analyzer report
130 | npm run build --report
131 | ```
132 |
133 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader).
134 |
135 | ---
136 | ## TODOs
137 |
138 | Some major TODOs:
139 | * error messages
140 | * implementing Datatypes
141 | * filter per columns
142 | * optional Modal before deleting
143 | * compatibility with CSS Frameworks (Bootstrap, Semantic, Foundation)
144 | * search & replace
145 | * edit multiple fields
146 | * statistics
147 |
148 | ---
149 | ## Contributions
150 |
151 | All contributions are welcome!
152 |
153 | ---
154 | ## License
155 |
156 | [MIT](http://opensource.org/licenses/MIT)
157 |
--------------------------------------------------------------------------------
/src/mixins/Validator.js:
--------------------------------------------------------------------------------
1 | import validator from 'validator';
2 |
3 | export default {
4 | methods: {
5 | validate(rules, messages, value) {
6 | const res = [];
7 | rules.forEach((rule, key) => {
8 | if (!this.makeValidation(rule, value)) {
9 | res.push(messages[key]);
10 | }
11 | });
12 | return res;
13 | },
14 | makeValidation(str, value) {
15 | let res = false;
16 | const arr = this.checkIfParameter(str);
17 | const l = arr.length;
18 | const string = arr[0];
19 | let paraOne;
20 | let paraTwo;
21 | if (l > 0) paraOne = arr[1];
22 | if (l > 1) paraTwo = arr[2];
23 | switch (string) {
24 | case 'required':
25 | res = !validator.isEmpty(value);
26 | break;
27 | case 'email':
28 | res = validator.isEmail(value);
29 | break;
30 | case 'contains':
31 | res = validator.contains(value, paraOne);
32 | break;
33 | case 'int':
34 | res = validator.isInt(value);
35 | break;
36 | case 'float':
37 | res = validator.isFloat(value);
38 | break;
39 | case 'min':
40 | if (validator.isInt(value)) {
41 | res = validator.isInt(value, { min: parseInt(paraOne, 10) });
42 | } else if (validator.isFloat(value)) {
43 | res = validator.isFloat(value, { min: parseFloat(paraOne, 10) });
44 | }
45 | break;
46 | case 'max':
47 | if (validator.isInt(value)) {
48 | res = validator.isInt(value, { max: parseInt(paraOne, 10) });
49 | } else if (validator.isFloat(value)) {
50 | res = validator.isFloat(value, { max: parseFloat(paraOne, 10) });
51 | }
52 | break;
53 | case 'between':
54 | if (validator.isInt(value)) {
55 | res = validator.isInt(value, { min: parseInt(paraOne, 10),
56 | max: parseInt(paraTwo, 10) });
57 | } else if (validator.isFloat(value)) {
58 | res = validator.isFloat(value, { min: parseFloat(paraOne, 10),
59 | max: parseFloat(paraTwo, 10) });
60 | }
61 | break;
62 | case 'gt':
63 | if (validator.isInt(value)) {
64 | res = validator.isInt(value, { gt: parseInt(paraOne, 10) });
65 | } else if (validator.isFloat(value)) {
66 | res = validator.isFloat(value, { gt: parseFloat(paraOne, 10) });
67 | }
68 | break;
69 | case 'lt':
70 | if (validator.isInt(value)) {
71 | res = validator.isInt(value, { lt: parseInt(paraOne, 10) });
72 | } else if (validator.isFloat(value)) {
73 | res = validator.isFloat(value, { lt: parseFloat(paraOne, 10) });
74 | }
75 | break;
76 | case 'alpha':
77 | res = validator.isAlpha(value, paraOne);
78 | break;
79 | case 'alphaNum':
80 | res = validator.isAlphanumeric(value, paraOne);
81 | break;
82 | case 'bool':
83 | res = validator.isBoolean(value);
84 | break;
85 | case 'url':
86 | res = validator.isURL(value);
87 | break;
88 | case 'fqdn':
89 | res = validator.isFQDN(value);
90 | break;
91 | case 'hexColor':
92 | res = validator.isHexColor(value);
93 | break;
94 | case 'ip4':
95 | res = validator.isIP(value, 4);
96 | break;
97 | case 'ip6':
98 | res = validator.isIP(value, 6);
99 | break;
100 | default:
101 | res = false;
102 | }
103 | return res;
104 | },
105 | checkIfParameter(str) {
106 | let i = 0;
107 | let res;
108 | i = str.indexOf(':');
109 | if (i > -1) {
110 | res = str.split(':');
111 | } else {
112 | res = [str];
113 | }
114 | return res;
115 | },
116 | },
117 | };
118 |
--------------------------------------------------------------------------------
/src/components/VueEditortable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | create
12 |
13 |
14 | delete
15 |
16 |
17 |
18 | remove_red_eye
19 |
20 |
21 |
22 | Show/Hide Column
23 |
24 |
25 |
26 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
50 |
51 |
52 |
53 | arrow_back
54 |
55 |
56 | arrow_forward
57 |
58 |
59 |
60 |
61 |
72 |
73 |
105 |
106 |
107 |
108 |
109 | |
114 | {{ col.title }}
115 |
116 |
117 | arrow_upward
118 | {{ sortOrderNumber(col.name) }}
119 |
120 | |
121 |
122 |
123 |
124 |
127 |
132 |
133 | {{ cell.value }}
134 |
147 |
148 |
149 |
150 |
151 | {{ cell.hasErrors[0] }}
152 | |
153 |
154 |
155 |
156 |
157 |
206 |
207 |
208 |
209 |
210 |
211 |
1256 |
1257 |
1595 |
1596 |
--------------------------------------------------------------------------------