├── .eslintignore ├── .storybook ├── addons.js ├── webpack.config.js └── config.js ├── .gitignore ├── .babelrc.js ├── stories ├── index.js └── components │ ├── FieldsCustom.vue │ └── FieldsStory.vue ├── src ├── components │ ├── Text.vue │ ├── Number.vue │ ├── Range.vue │ ├── Textarea.vue │ ├── Checkbox.vue │ ├── Radio.vue │ └── Select.vue ├── index.js ├── field.js ├── util.js └── fields.vue ├── .circleci └── config.yml ├── rollup.config.js ├── README.md ├── package.json ├── .eslintrc.js └── dist ├── vue-fields.min.js ├── vue-fields.esm.js ├── vue-fields.common.js └── vue-fields.js /.eslintignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-actions/register'; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | yarn-error.log 3 | .DS_Store 4 | .history 5 | .idea 6 | -------------------------------------------------------------------------------- /.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 3 | presets: [ 4 | ['@babel/preset-env', { 5 | loose: true, 6 | modules: false 7 | }] 8 | ] 9 | 10 | }; 11 | -------------------------------------------------------------------------------- /stories/index.js: -------------------------------------------------------------------------------- 1 | import FieldsStory from './components/FieldsStory.vue'; 2 | import {storiesOf} from '@storybook/vue'; 3 | 4 | storiesOf('Fields', module) 5 | .add('Default', () => FieldsStory); 6 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = ({config}) => { 4 | 5 | // add fields alias 6 | config.resolve.alias['vue-fields'] = path.resolve(__dirname, '../src') 7 | 8 | return config; 9 | }; -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueFields from 'vue-fields'; 3 | import {configure} from '@storybook/vue'; 4 | 5 | Vue.use(VueFields); 6 | 7 | configure(() => { 8 | 9 | require('../stories'); 10 | 11 | }, module); -------------------------------------------------------------------------------- /src/components/Text.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/components/Number.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/components/Range.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/components/Textarea.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/components/Checkbox.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/components/Radio.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /stories/components/FieldsCustom.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/components/Select.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Install plugin. 3 | */ 4 | 5 | import Field from './field'; 6 | import Fields from './fields.vue'; 7 | import Util, {log} from './util'; 8 | 9 | const Plugin = { 10 | 11 | Field, 12 | Fields, 13 | 14 | install(Vue) { 15 | 16 | if (this.installed) { 17 | return; 18 | } 19 | 20 | Util(Vue); log(this.version); 21 | 22 | Vue.component('field', Field); 23 | Vue.component('fields', Fields); 24 | }, 25 | 26 | version: '__VERSION__' 27 | }; 28 | 29 | if (typeof window !== 'undefined' && window.Vue) { 30 | window.Vue.use(Plugin); 31 | } 32 | 33 | export default Plugin; -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | defaults: &defaults 4 | docker: 5 | - image: circleci/node:10-browsers 6 | environment: 7 | CHROME_BIN: /usr/bin/google-chrome 8 | working_directory: ~/vue-fields 9 | 10 | jobs: 11 | build: 12 | <<: *defaults 13 | steps: 14 | - checkout 15 | - restore_cache: 16 | key: yarn-{{ checksum "yarn.lock" }} 17 | - run: 18 | name: Install Dependencies 19 | command: yarn install --pure-lockfile 20 | - save_cache: 21 | key: yarn-{{ checksum "yarn.lock" }} 22 | paths: 23 | - ./node_modules 24 | - run: 25 | name: Run ESLint 26 | command: yarn eslint 27 | - run: 28 | name: Build Release 29 | command: yarn build -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | const vue = require('rollup-plugin-vue'); 4 | const babel = require('rollup-plugin-babel'); 5 | const replace = require('rollup-plugin-replace'); 6 | const {uglify} = require('rollup-plugin-uglify'); 7 | const {name, version, homepage} = require('./package.json'); 8 | const license = 9 | '/*!\n' + 10 | ' * ' + name + ' v' + version + '\n' + 11 | ' * ' + homepage + '\n' + 12 | ' * Released under the MIT License.\n' + 13 | ' */\n'; 14 | 15 | module.exports = [ 16 | 17 | { 18 | file: `dist/${name}.js`, 19 | name: 'VueFields', 20 | format: 'umd' 21 | }, 22 | { 23 | file: `dist/${name}.min.js`, 24 | name: 'VueFields', 25 | format: 'umd', 26 | plugins: [uglify({output: {preamble: license}})] 27 | }, 28 | { 29 | file: `dist/${name}.esm.js`, 30 | format: 'es', 31 | footer: 'export {Field, Fields};' 32 | }, 33 | { 34 | file: `dist/${name}.common.js`, 35 | format: 'cjs', 36 | } 37 | 38 | ].map(output => ({ 39 | 40 | input: 'src/index.js', 41 | output: {banner: license, ...output}, 42 | plugins: [ 43 | vue(), 44 | babel({extensions: ['.js', '.vue']}), 45 | replace({__VERSION__: version}), 46 | ].concat(output.plugins) 47 | 48 | })); 49 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-fields [![Build](https://circleci.com/gh/pagekit/vue-fields.svg?style=shield)](https://circleci.com/gh/pagekit/vue-fields) [![Downloads](https://img.shields.io/npm/dm/vue-fields.svg)](https://www.npmjs.com/package/vue-fields) [![Version](https://img.shields.io/npm/v/vue-fields.svg)](https://www.npmjs.com/package/vue-fields) [![License](https://img.shields.io/npm/l/vue-fields.svg)](https://www.npmjs.com/package/vue-fields) 2 | 3 | The form fields generator for [Vue.js](http://vuejs.org). 4 | 5 | ## Features 6 | 7 | - Supports latest Firefox, Chrome, Safari, Opera and IE9+ 8 | - Supports Vue 2.0 9 | - Compact size 6KB (2KB gzipped) 10 | 11 | ## Installation 12 | You can install it via [yarn](https://yarnpkg.com/) or [NPM](http://npmjs.org/). 13 | ``` 14 | $ yarn add vue-fields 15 | $ npm install vue-fields 16 | ``` 17 | 18 | ### CDN 19 | Available on [jsdelivr](https://cdn.jsdelivr.net/npm/vue-fields@1.1.3) or [unpkg](https://unpkg.com/vue-fields@1.1.3). 20 | ```html 21 | 22 | ``` 23 | 24 | ## Changelog 25 | 26 | Details changes for each release are documented in the [release notes](https://github.com/pagekit/vue-fields/releases). 27 | 28 | ## Contribution 29 | 30 | If you find a bug or want to contribute to the code or documentation, you can help by submitting an [issue](https://github.com/pagekit/vue-fields/issues) or a [pull request](https://github.com/pagekit/vue-fields/pulls). 31 | 32 | ## License 33 | 34 | [MIT](http://opensource.org/licenses/MIT) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-fields", 3 | "version": "1.1.3", 4 | "description": "The form fields generator for Vue.js", 5 | "homepage": "https://github.com/pagekit/vue-fields", 6 | "license": "MIT", 7 | "main": "dist/vue-fields.common.js", 8 | "module": "dist/vue-fields.esm.js", 9 | "unpkg": "dist/vue-fields.min.js", 10 | "jsdelivr": "dist/vue-fields.min.js", 11 | "files": [ 12 | "src", 13 | "dist" 14 | ], 15 | "keywords": [ 16 | "vue", 17 | "vuejs", 18 | "mvvm" 19 | ], 20 | "bugs": { 21 | "url": "https://github.com/pagekit/vue-fields/issues" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "git+https://github.com/pagekit/vue-fields.git" 26 | }, 27 | "scripts": { 28 | "up": "yarn upgrade-interactive --latest", 29 | "build": "rollup -c", 30 | "release": "node ./build/release.js", 31 | "eslint": "eslint . --ext .js,.vue", 32 | "eslint-fix": "eslint . --ext .js,.vue --fix", 33 | "storybook": "start-storybook -c .storybook -p 9001" 34 | }, 35 | "devDependencies": { 36 | "@babel/core": "^7.4.5", 37 | "@babel/preset-env": "^7.4.5", 38 | "@storybook/addon-actions": "^5.0.0", 39 | "@storybook/vue": "^5.0.0", 40 | "babel-loader": "^8.0.5", 41 | "babel-preset-vue": "^2.0.2", 42 | "eslint": "^5.16.0", 43 | "eslint-plugin-vue": "^4.7.0", 44 | "replace-in-file": "^4.1.0", 45 | "rollup": "^0.68.2", 46 | "rollup-plugin-babel": "^4.3.2", 47 | "rollup-plugin-replace": "^2.2.0", 48 | "rollup-plugin-uglify": "^6.0.2", 49 | "rollup-plugin-vue": "^3.0.0", 50 | "vue": "^2.6.10", 51 | "vue-loader": "^15.7.0", 52 | "vue-template-compiler": "^2.6.10" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "root": true, 3 | "env": { 4 | "es6": true, 5 | "browser": true, 6 | "commonjs": true, 7 | }, 8 | "plugins": [ 9 | "vue" 10 | ], 11 | "extends": [ 12 | "eslint:recommended", 13 | "plugin:vue/recommended" 14 | ], 15 | "parserOptions": { 16 | "sourceType": "module" 17 | }, 18 | "rules": { 19 | "brace-style": ["error", "1tbs", {"allowSingleLine": true}], 20 | "comma-spacing": "error", 21 | "comma-style": "error", 22 | "eqeqeq": ["off", "smart"], 23 | "indent": "off", 24 | "indent-legacy": ["error", 4, {"SwitchCase": 1}], 25 | "key-spacing": "error", 26 | "keyword-spacing": "error", 27 | "linebreak-style": ["error", "unix"], 28 | "no-array-constructor": "error", 29 | "no-console": "off", 30 | "no-duplicate-imports": "error", 31 | "no-empty": ["error", {"allowEmptyCatch": true}], 32 | "no-extend-native": "error", 33 | "no-lone-blocks": "error", 34 | "no-multi-spaces": "error", 35 | "no-multiple-empty-lines": "error", 36 | "no-template-curly-in-string": "error", 37 | "no-trailing-spaces": "error", 38 | "no-unused-vars": ["error", {"vars": "local", "args": "none"}], 39 | "no-var": "error", 40 | "object-curly-spacing": "error", 41 | "prefer-const": "error", 42 | "quotes": ["error", "single", {"avoidEscape": true}], 43 | "semi": ["error", "always"], 44 | "space-before-blocks": "error", 45 | "space-in-parens": "error", 46 | "space-infix-ops": "error", 47 | "space-unary-ops": "error", 48 | "template-curly-spacing": "error", 49 | "vue/html-indent": ["error", 4], 50 | "vue/html-self-closing": ["error", {"html": {"normal": "never"}}], 51 | "vue/max-attributes-per-line": "off", 52 | "vue/require-default-prop": "off", 53 | "vue/require-v-for-key": "off" 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /src/field.js: -------------------------------------------------------------------------------- 1 | import {get, each, warn, assign, isObject, isUndefined} from './util'; 2 | 3 | export default { 4 | 5 | inject: ['Fields'], 6 | 7 | props: { 8 | 9 | field: { 10 | type: Object, 11 | required: true 12 | }, 13 | 14 | values: { 15 | type: Object, 16 | required: true 17 | } 18 | 19 | }, 20 | 21 | data() { 22 | return assign({ 23 | name: '', 24 | label: '', 25 | attrs: {}, 26 | options: [], 27 | default: undefined 28 | }, this.field); 29 | }, 30 | 31 | computed: { 32 | 33 | value: { 34 | 35 | get() { 36 | return get(this.values, this.name); 37 | }, 38 | 39 | set(value) { 40 | this.$emit('change', value, this); 41 | } 42 | 43 | }, 44 | 45 | attributes: { 46 | 47 | get() { 48 | 49 | if (!this.Fields.evaluate(this.enable)) { 50 | return assign({disabled: 'true'}, this.attrs); 51 | } 52 | 53 | return this.attrs; 54 | } 55 | 56 | }, 57 | 58 | }, 59 | 60 | created() { 61 | 62 | if (isUndefined(this.value) && !isUndefined(this.default)) { 63 | this.value = this.default; 64 | } 65 | 66 | }, 67 | 68 | methods: { 69 | 70 | filterOptions(options) { 71 | 72 | const opts = []; 73 | 74 | if (!options) { 75 | warn(`Invalid options provided for ${this.name}`); 76 | return opts; 77 | } 78 | 79 | each(options, (value, name) => { 80 | if (isObject(value)) { 81 | opts.push({label: name, options: this.filterOptions(value)}); 82 | } else { 83 | opts.push({text: name, value: value}); 84 | } 85 | }); 86 | 87 | return opts; 88 | } 89 | 90 | } 91 | 92 | }; 93 | -------------------------------------------------------------------------------- /stories/components/FieldsStory.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 120 | 121 | 126 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Utility functions. 3 | */ 4 | 5 | let _config = {}, _set; 6 | 7 | export const assign = Object.assign || _assign; 8 | 9 | export const isArray = Array.isArray; 10 | 11 | export default function ({set, config}) { 12 | _set = set; 13 | _config = config; 14 | } 15 | 16 | export function log(message, color = '#41B883') { 17 | if (typeof console !== 'undefined' && _config.devtools) { 18 | console.log(`%c vue-fields %c ${message} `, 'color: #fff; background: #35495E; padding: 1px; border-radius: 3px 0 0 3px;', `color: #fff; background: ${color}; padding: 1px; border-radius: 0 3px 3px 0;`); 19 | } 20 | } 21 | 22 | export function warn(message, color = '#DB6B00') { 23 | log(message, color); 24 | } 25 | 26 | export function isObject(obj) { 27 | return obj !== null && typeof obj === 'object'; 28 | } 29 | 30 | export function isString(val) { 31 | return typeof val === 'string'; 32 | } 33 | 34 | export function isFunction(val) { 35 | return typeof val === 'function'; 36 | } 37 | 38 | export function isUndefined(val) { 39 | return typeof val === 'undefined'; 40 | } 41 | 42 | export function get(obj, key, def) { 43 | 44 | const parts = isArray(key) ? key : key.split('.'); 45 | 46 | for (let i = 0; i < parts.length; i++) { 47 | if (isObject(obj) && !isUndefined(obj[parts[i]])) { 48 | obj = obj[parts[i]]; 49 | } else { 50 | return def; 51 | } 52 | } 53 | 54 | return obj; 55 | } 56 | 57 | export function set(obj, key, val) { 58 | 59 | const parts = isArray(key) ? key : key.split('.'); 60 | 61 | while (parts.length > 1) { 62 | 63 | const part = parts.shift(); 64 | 65 | if (!isObject(obj[part])) { 66 | _set(obj, part, {}); 67 | } 68 | 69 | obj = obj[part]; 70 | } 71 | 72 | _set(obj, parts.shift(), val); 73 | } 74 | 75 | const parsedFunc = {}; 76 | const expressionRe = /((?:\d|true|false|null|undefined|(?:this\.|\$)[\w.$]+|\W)*)([\w][\w.-]*)?/g; 77 | const quotedStringRe = /([^"']+)((.)(?:[^\3\\]|\\.)*?\3|.)?/g; 78 | 79 | export function parse(expr) { 80 | return parsedFunc[expr] = parsedFunc[expr] || 81 | Function('$values', '$context', `with($context){return ${expr.replace(quotedStringRe, 82 | (match, unquoted, quoted = '') => unquoted.replace(expressionRe, 83 | (match, prefix = '', expression) => match ? `${prefix}${expression ? `$get('${expression}')` : ''}` : '' 84 | ) + quoted 85 | )}}`); 86 | } 87 | 88 | export function each(obj, iterator) { 89 | 90 | let i, key; 91 | 92 | if (typeof obj.length == 'number') { 93 | for (i = 0; i < obj.length; i++) { 94 | iterator.call(obj[i], obj[i], i); 95 | } 96 | } else if (isObject(obj)) { 97 | for (key in obj) { 98 | if (obj.hasOwnProperty(key)) { 99 | iterator.call(obj[key], obj[key], key); 100 | } 101 | } 102 | } 103 | 104 | return obj; 105 | } 106 | 107 | /** 108 | * Object.assign() polyfill. 109 | */ 110 | function _assign(target, ...sources) { 111 | 112 | sources.forEach(source => { 113 | Object.keys(source || {}).forEach( 114 | key => target[key] = source[key] 115 | ); 116 | }); 117 | 118 | return target; 119 | } 120 | -------------------------------------------------------------------------------- /src/fields.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 142 | -------------------------------------------------------------------------------- /dist/vue-fields.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-fields v1.1.3 3 | * https://github.com/pagekit/vue-fields 4 | * Released under the MIT License. 5 | */ 6 | 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).VueFields=t()}(this,function(){"use strict";var a,r={},u=Object.assign||function(n){for(var e=arguments.length,t=new Array(1 1) { 66 | var part = parts.shift(); 67 | 68 | if (!isObject(obj[part])) { 69 | _set(obj, part, {}); 70 | } 71 | 72 | obj = obj[part]; 73 | } 74 | 75 | _set(obj, parts.shift(), val); 76 | } 77 | var parsedFunc = {}; 78 | var expressionRe = /((?:\d|true|false|null|undefined|(?:this\.|\$)[\w.$]+|\W)*)([\w][\w.-]*)?/g; 79 | var quotedStringRe = /([^"']+)((.)(?:[^\3\\]|\\.)*?\3|.)?/g; 80 | function parse(expr) { 81 | return parsedFunc[expr] = parsedFunc[expr] || Function('$values', '$context', "with($context){return " + expr.replace(quotedStringRe, function (match, unquoted, quoted) { 82 | if (quoted === void 0) { 83 | quoted = ''; 84 | } 85 | 86 | return unquoted.replace(expressionRe, function (match, prefix, expression) { 87 | if (prefix === void 0) { 88 | prefix = ''; 89 | } 90 | 91 | return match ? "" + prefix + (expression ? "$get('" + expression + "')" : '') : ''; 92 | }) + quoted; 93 | }) + "}"); 94 | } 95 | function each(obj, iterator) { 96 | var i, key; 97 | 98 | if (typeof obj.length == 'number') { 99 | for (i = 0; i < obj.length; i++) { 100 | iterator.call(obj[i], obj[i], i); 101 | } 102 | } else if (isObject(obj)) { 103 | for (key in obj) { 104 | if (obj.hasOwnProperty(key)) { 105 | iterator.call(obj[key], obj[key], key); 106 | } 107 | } 108 | } 109 | 110 | return obj; 111 | } 112 | /** 113 | * Object.assign() polyfill. 114 | */ 115 | 116 | function _assign(target) { 117 | for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 118 | sources[_key - 1] = arguments[_key]; 119 | } 120 | 121 | sources.forEach(function (source) { 122 | Object.keys(source || {}).forEach(function (key) { 123 | return target[key] = source[key]; 124 | }); 125 | }); 126 | return target; 127 | } 128 | 129 | var Field = { 130 | inject: ['Fields'], 131 | props: { 132 | field: { 133 | type: Object, 134 | required: true 135 | }, 136 | values: { 137 | type: Object, 138 | required: true 139 | } 140 | }, 141 | data: function data() { 142 | return assign({ 143 | name: '', 144 | label: '', 145 | attrs: {}, 146 | options: [], 147 | "default": undefined 148 | }, this.field); 149 | }, 150 | computed: { 151 | value: { 152 | get: function get$$1() { 153 | return get(this.values, this.name); 154 | }, 155 | set: function set$$1(value) { 156 | this.$emit('change', value, this); 157 | } 158 | }, 159 | attributes: { 160 | get: function get$$1() { 161 | if (!this.Fields.evaluate(this.enable)) { 162 | return assign({ 163 | disabled: 'true' 164 | }, this.attrs); 165 | } 166 | 167 | return this.attrs; 168 | } 169 | } 170 | }, 171 | created: function created() { 172 | if (isUndefined(this.value) && !isUndefined(this["default"])) { 173 | this.value = this["default"]; 174 | } 175 | }, 176 | methods: { 177 | filterOptions: function filterOptions(options) { 178 | var _this = this; 179 | 180 | var opts = []; 181 | 182 | if (!options) { 183 | warn("Invalid options provided for " + this.name); 184 | return opts; 185 | } 186 | 187 | each(options, function (value, name) { 188 | if (isObject(value)) { 189 | opts.push({ 190 | label: name, 191 | options: _this.filterOptions(value) 192 | }); 193 | } else { 194 | opts.push({ 195 | text: name, 196 | value: value 197 | }); 198 | } 199 | }); 200 | return opts; 201 | } 202 | } 203 | }; 204 | 205 | var FieldText = { 206 | render: function render() { 207 | var _vm = this; 208 | 209 | var _h = _vm.$createElement; 210 | 211 | var _c = _vm._self._c || _h; 212 | 213 | return _c('input', _vm._b({ 214 | directives: [{ 215 | name: "model", 216 | rawName: "v-model", 217 | value: _vm.value, 218 | expression: "value" 219 | }], 220 | attrs: { 221 | "type": "text" 222 | }, 223 | domProps: { 224 | "value": _vm.value 225 | }, 226 | on: { 227 | "input": function input($event) { 228 | if ($event.target.composing) { 229 | return; 230 | } 231 | 232 | _vm.value = $event.target.value; 233 | } 234 | } 235 | }, 'input', _vm.attributes, false)); 236 | }, 237 | staticRenderFns: [], 238 | "extends": Field 239 | }; 240 | 241 | var FieldTextarea = { 242 | render: function render() { 243 | var _vm = this; 244 | 245 | var _h = _vm.$createElement; 246 | 247 | var _c = _vm._self._c || _h; 248 | 249 | return _c('textarea', _vm._b({ 250 | directives: [{ 251 | name: "model", 252 | rawName: "v-model", 253 | value: _vm.value, 254 | expression: "value" 255 | }], 256 | domProps: { 257 | "value": _vm.value 258 | }, 259 | on: { 260 | "input": function input($event) { 261 | if ($event.target.composing) { 262 | return; 263 | } 264 | 265 | _vm.value = $event.target.value; 266 | } 267 | } 268 | }, 'textarea', _vm.attributes, false)); 269 | }, 270 | staticRenderFns: [], 271 | "extends": Field 272 | }; 273 | 274 | var FieldRadio = { 275 | render: function render() { 276 | var _vm = this; 277 | 278 | var _h = _vm.$createElement; 279 | 280 | var _c = _vm._self._c || _h; 281 | 282 | return _c('div', [_vm._l(_vm.filterOptions(_vm.options), function (option) { 283 | return [_c('input', _vm._b({ 284 | directives: [{ 285 | name: "model", 286 | rawName: "v-model", 287 | value: _vm.value, 288 | expression: "value" 289 | }], 290 | attrs: { 291 | "name": _vm.name, 292 | "type": "radio" 293 | }, 294 | domProps: { 295 | "value": option.value, 296 | "checked": _vm._q(_vm.value, option.value) 297 | }, 298 | on: { 299 | "change": function change($event) { 300 | _vm.value = option.value; 301 | } 302 | } 303 | }, 'input', _vm.attributes, false)), _vm._v(" "), _c('label', [_vm._v(_vm._s(option.text))])]; 304 | })], 2); 305 | }, 306 | staticRenderFns: [], 307 | "extends": Field 308 | }; 309 | 310 | var FieldCheckbox = { 311 | render: function render() { 312 | var _vm = this; 313 | 314 | var _h = _vm.$createElement; 315 | 316 | var _c = _vm._self._c || _h; 317 | 318 | return _c('input', _vm._b({ 319 | directives: [{ 320 | name: "model", 321 | rawName: "v-model", 322 | value: _vm.value, 323 | expression: "value" 324 | }], 325 | attrs: { 326 | "type": "checkbox" 327 | }, 328 | domProps: { 329 | "checked": Array.isArray(_vm.value) ? _vm._i(_vm.value, null) > -1 : _vm.value 330 | }, 331 | on: { 332 | "change": function change($event) { 333 | var $$a = _vm.value, 334 | $$el = $event.target, 335 | $$c = $$el.checked ? true : false; 336 | 337 | if (Array.isArray($$a)) { 338 | var $$v = null, 339 | $$i = _vm._i($$a, $$v); 340 | 341 | if ($$el.checked) { 342 | $$i < 0 && (_vm.value = $$a.concat([$$v])); 343 | } else { 344 | $$i > -1 && (_vm.value = $$a.slice(0, $$i).concat($$a.slice($$i + 1))); 345 | } 346 | } else { 347 | _vm.value = $$c; 348 | } 349 | } 350 | } 351 | }, 'input', _vm.attributes, false)); 352 | }, 353 | staticRenderFns: [], 354 | "extends": Field 355 | }; 356 | 357 | var FieldSelect = { 358 | render: function render() { 359 | var _vm = this; 360 | 361 | var _h = _vm.$createElement; 362 | 363 | var _c = _vm._self._c || _h; 364 | 365 | return _c('select', _vm._b({ 366 | directives: [{ 367 | name: "model", 368 | rawName: "v-model", 369 | value: _vm.value, 370 | expression: "value" 371 | }], 372 | on: { 373 | "change": function change($event) { 374 | var $$selectedVal = Array.prototype.filter.call($event.target.options, function (o) { 375 | return o.selected; 376 | }).map(function (o) { 377 | var val = "_value" in o ? o._value : o.value; 378 | return val; 379 | }); 380 | _vm.value = $event.target.multiple ? $$selectedVal : $$selectedVal[0]; 381 | } 382 | } 383 | }, 'select', _vm.attributes, false), [_vm._l(_vm.filterOptions(_vm.options), function (option) { 384 | return [option.label ? _c('optgroup', { 385 | attrs: { 386 | "label": option.label 387 | } 388 | }, _vm._l(option.options, function (opt) { 389 | return _c('option', { 390 | domProps: { 391 | "value": opt.value 392 | } 393 | }, [_vm._v(_vm._s(opt.text))]); 394 | }), 0) : _c('option', { 395 | domProps: { 396 | "value": option.value 397 | } 398 | }, [_vm._v(_vm._s(option.text))])]; 399 | })], 2); 400 | }, 401 | staticRenderFns: [], 402 | "extends": Field 403 | }; 404 | 405 | var FieldRange = { 406 | render: function render() { 407 | var _vm = this; 408 | 409 | var _h = _vm.$createElement; 410 | 411 | var _c = _vm._self._c || _h; 412 | 413 | return _c('input', _vm._b({ 414 | directives: [{ 415 | name: "model", 416 | rawName: "v-model", 417 | value: _vm.value, 418 | expression: "value" 419 | }], 420 | attrs: { 421 | "type": "range" 422 | }, 423 | domProps: { 424 | "value": _vm.value 425 | }, 426 | on: { 427 | "__r": function __r($event) { 428 | _vm.value = $event.target.value; 429 | } 430 | } 431 | }, 'input', _vm.attributes, false)); 432 | }, 433 | staticRenderFns: [], 434 | "extends": Field 435 | }; 436 | 437 | var FieldNumber = { 438 | render: function render() { 439 | var _vm = this; 440 | 441 | var _h = _vm.$createElement; 442 | 443 | var _c = _vm._self._c || _h; 444 | 445 | return _c('input', _vm._b({ 446 | directives: [{ 447 | name: "model", 448 | rawName: "v-model", 449 | value: _vm.value, 450 | expression: "value" 451 | }], 452 | attrs: { 453 | "type": "number" 454 | }, 455 | domProps: { 456 | "value": _vm.value 457 | }, 458 | on: { 459 | "input": function input($event) { 460 | if ($event.target.composing) { 461 | return; 462 | } 463 | 464 | _vm.value = $event.target.value; 465 | } 466 | } 467 | }, 'input', _vm.attributes, false)); 468 | }, 469 | staticRenderFns: [], 470 | "extends": Field 471 | }; 472 | 473 | var Fields = { 474 | render: function render() { 475 | var _vm = this; 476 | 477 | var _h = _vm.$createElement; 478 | 479 | var _c = _vm._self._c || _h; 480 | 481 | return _c('div', _vm._l(_vm.fields, function (field) { 482 | return _c('div', { 483 | directives: [{ 484 | name: "show", 485 | rawName: "v-show", 486 | value: _vm.evaluate(field.show), 487 | expression: "evaluate(field.show)" 488 | }], 489 | key: field.name 490 | }, [field.type != 'checkbox' ? _c('label', [_vm._v(_vm._s(field.label))]) : _vm._e(), _vm._v(" "), _c(field.component, { 491 | tag: "component", 492 | attrs: { 493 | "field": field, 494 | "values": _vm.values 495 | }, 496 | on: { 497 | "change": _vm.change 498 | } 499 | })], 1); 500 | }), 0); 501 | }, 502 | staticRenderFns: [], 503 | components: { 504 | FieldText: FieldText, 505 | FieldTextarea: FieldTextarea, 506 | FieldRadio: FieldRadio, 507 | FieldCheckbox: FieldCheckbox, 508 | FieldSelect: FieldSelect, 509 | FieldRange: FieldRange, 510 | FieldNumber: FieldNumber 511 | }, 512 | provide: function provide() { 513 | return { 514 | Fields: this 515 | }; 516 | }, 517 | props: { 518 | config: { 519 | type: [Object, Array], 520 | "default": function _default() { 521 | return {}; 522 | } 523 | }, 524 | values: { 525 | type: Object, 526 | "default": function _default() { 527 | return {}; 528 | } 529 | }, 530 | prefix: { 531 | type: String, 532 | "default": 'field-' 533 | } 534 | }, 535 | computed: { 536 | fields: function fields() { 537 | return this.prepare(); 538 | } 539 | }, 540 | methods: { 541 | change: function change(value, field) { 542 | set(this.values, field.name, value); 543 | this.$emit('change', value, field); 544 | }, 545 | prepare: function prepare(config, prefix) { 546 | if (config === void 0) { 547 | config = this.config; 548 | } 549 | 550 | if (prefix === void 0) { 551 | prefix = this.prefix; 552 | } 553 | 554 | var arr = isArray(config), 555 | fields = []; 556 | each(config, function (field, key) { 557 | field = assign({}, field); 558 | 559 | if (!field.name && !arr) { 560 | field.name = key; 561 | } 562 | 563 | if (field.name) { 564 | if (!field.type) { 565 | field.type = 'text'; 566 | } 567 | 568 | if (!field.component) { 569 | field.component = prefix + field.type; 570 | } 571 | 572 | fields.push(field); 573 | } else { 574 | warn("Field name missing " + JSON.stringify(field)); 575 | } 576 | }); 577 | return fields; 578 | }, 579 | evaluate: function evaluate(expression, values) { 580 | if (values === void 0) { 581 | values = this.values; 582 | } 583 | 584 | try { 585 | if (isUndefined(expression)) { 586 | return true; 587 | } 588 | 589 | if (isString(expression)) { 590 | expression = parse(expression); 591 | } 592 | 593 | if (isFunction(expression)) { 594 | return expression.call(this, values, { 595 | $match: $match, 596 | $get: function $get(key) { 597 | return get(values, key); 598 | } 599 | }); 600 | } 601 | 602 | return expression; 603 | } catch (e) { 604 | warn(e); 605 | } 606 | 607 | return true; 608 | } 609 | } 610 | }; 611 | 612 | function $match(subject, pattern, flags) { 613 | return subject && new RegExp(pattern, flags).test(subject); 614 | } 615 | 616 | /** 617 | * Install plugin. 618 | */ 619 | var Plugin = { 620 | Field: Field, 621 | Fields: Fields, 622 | install: function install(Vue) { 623 | if (this.installed) { 624 | return; 625 | } 626 | 627 | Util(Vue); 628 | log(this.version); 629 | Vue.component('field', Field); 630 | Vue.component('fields', Fields); 631 | }, 632 | version: '1.1.3' 633 | }; 634 | 635 | if (typeof window !== 'undefined' && window.Vue) { 636 | window.Vue.use(Plugin); 637 | } 638 | 639 | export default Plugin; 640 | export {Field, Fields}; 641 | -------------------------------------------------------------------------------- /dist/vue-fields.common.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-fields v1.1.3 3 | * https://github.com/pagekit/vue-fields 4 | * Released under the MIT License. 5 | */ 6 | 7 | 'use strict'; 8 | 9 | /** 10 | * Utility functions. 11 | */ 12 | var _config = {}, 13 | _set; 14 | 15 | var assign = Object.assign || _assign; 16 | var isArray = Array.isArray; 17 | function Util (_ref) { 18 | var set = _ref.set, 19 | config = _ref.config; 20 | _set = set; 21 | _config = config; 22 | } 23 | function log(message, color) { 24 | if (color === void 0) { 25 | color = '#41B883'; 26 | } 27 | 28 | if (typeof console !== 'undefined' && _config.devtools) { 29 | console.log("%c vue-fields %c " + message + " ", 'color: #fff; background: #35495E; padding: 1px; border-radius: 3px 0 0 3px;', "color: #fff; background: " + color + "; padding: 1px; border-radius: 0 3px 3px 0;"); 30 | } 31 | } 32 | function warn(message, color) { 33 | if (color === void 0) { 34 | color = '#DB6B00'; 35 | } 36 | 37 | log(message, color); 38 | } 39 | function isObject(obj) { 40 | return obj !== null && typeof obj === 'object'; 41 | } 42 | function isString(val) { 43 | return typeof val === 'string'; 44 | } 45 | function isFunction(val) { 46 | return typeof val === 'function'; 47 | } 48 | function isUndefined(val) { 49 | return typeof val === 'undefined'; 50 | } 51 | function get(obj, key, def) { 52 | var parts = isArray(key) ? key : key.split('.'); 53 | 54 | for (var i = 0; i < parts.length; i++) { 55 | if (isObject(obj) && !isUndefined(obj[parts[i]])) { 56 | obj = obj[parts[i]]; 57 | } else { 58 | return def; 59 | } 60 | } 61 | 62 | return obj; 63 | } 64 | function set(obj, key, val) { 65 | var parts = isArray(key) ? key : key.split('.'); 66 | 67 | while (parts.length > 1) { 68 | var part = parts.shift(); 69 | 70 | if (!isObject(obj[part])) { 71 | _set(obj, part, {}); 72 | } 73 | 74 | obj = obj[part]; 75 | } 76 | 77 | _set(obj, parts.shift(), val); 78 | } 79 | var parsedFunc = {}; 80 | var expressionRe = /((?:\d|true|false|null|undefined|(?:this\.|\$)[\w.$]+|\W)*)([\w][\w.-]*)?/g; 81 | var quotedStringRe = /([^"']+)((.)(?:[^\3\\]|\\.)*?\3|.)?/g; 82 | function parse(expr) { 83 | return parsedFunc[expr] = parsedFunc[expr] || Function('$values', '$context', "with($context){return " + expr.replace(quotedStringRe, function (match, unquoted, quoted) { 84 | if (quoted === void 0) { 85 | quoted = ''; 86 | } 87 | 88 | return unquoted.replace(expressionRe, function (match, prefix, expression) { 89 | if (prefix === void 0) { 90 | prefix = ''; 91 | } 92 | 93 | return match ? "" + prefix + (expression ? "$get('" + expression + "')" : '') : ''; 94 | }) + quoted; 95 | }) + "}"); 96 | } 97 | function each(obj, iterator) { 98 | var i, key; 99 | 100 | if (typeof obj.length == 'number') { 101 | for (i = 0; i < obj.length; i++) { 102 | iterator.call(obj[i], obj[i], i); 103 | } 104 | } else if (isObject(obj)) { 105 | for (key in obj) { 106 | if (obj.hasOwnProperty(key)) { 107 | iterator.call(obj[key], obj[key], key); 108 | } 109 | } 110 | } 111 | 112 | return obj; 113 | } 114 | /** 115 | * Object.assign() polyfill. 116 | */ 117 | 118 | function _assign(target) { 119 | for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 120 | sources[_key - 1] = arguments[_key]; 121 | } 122 | 123 | sources.forEach(function (source) { 124 | Object.keys(source || {}).forEach(function (key) { 125 | return target[key] = source[key]; 126 | }); 127 | }); 128 | return target; 129 | } 130 | 131 | var Field = { 132 | inject: ['Fields'], 133 | props: { 134 | field: { 135 | type: Object, 136 | required: true 137 | }, 138 | values: { 139 | type: Object, 140 | required: true 141 | } 142 | }, 143 | data: function data() { 144 | return assign({ 145 | name: '', 146 | label: '', 147 | attrs: {}, 148 | options: [], 149 | "default": undefined 150 | }, this.field); 151 | }, 152 | computed: { 153 | value: { 154 | get: function get$$1() { 155 | return get(this.values, this.name); 156 | }, 157 | set: function set$$1(value) { 158 | this.$emit('change', value, this); 159 | } 160 | }, 161 | attributes: { 162 | get: function get$$1() { 163 | if (!this.Fields.evaluate(this.enable)) { 164 | return assign({ 165 | disabled: 'true' 166 | }, this.attrs); 167 | } 168 | 169 | return this.attrs; 170 | } 171 | } 172 | }, 173 | created: function created() { 174 | if (isUndefined(this.value) && !isUndefined(this["default"])) { 175 | this.value = this["default"]; 176 | } 177 | }, 178 | methods: { 179 | filterOptions: function filterOptions(options) { 180 | var _this = this; 181 | 182 | var opts = []; 183 | 184 | if (!options) { 185 | warn("Invalid options provided for " + this.name); 186 | return opts; 187 | } 188 | 189 | each(options, function (value, name) { 190 | if (isObject(value)) { 191 | opts.push({ 192 | label: name, 193 | options: _this.filterOptions(value) 194 | }); 195 | } else { 196 | opts.push({ 197 | text: name, 198 | value: value 199 | }); 200 | } 201 | }); 202 | return opts; 203 | } 204 | } 205 | }; 206 | 207 | var FieldText = { 208 | render: function render() { 209 | var _vm = this; 210 | 211 | var _h = _vm.$createElement; 212 | 213 | var _c = _vm._self._c || _h; 214 | 215 | return _c('input', _vm._b({ 216 | directives: [{ 217 | name: "model", 218 | rawName: "v-model", 219 | value: _vm.value, 220 | expression: "value" 221 | }], 222 | attrs: { 223 | "type": "text" 224 | }, 225 | domProps: { 226 | "value": _vm.value 227 | }, 228 | on: { 229 | "input": function input($event) { 230 | if ($event.target.composing) { 231 | return; 232 | } 233 | 234 | _vm.value = $event.target.value; 235 | } 236 | } 237 | }, 'input', _vm.attributes, false)); 238 | }, 239 | staticRenderFns: [], 240 | "extends": Field 241 | }; 242 | 243 | var FieldTextarea = { 244 | render: function render() { 245 | var _vm = this; 246 | 247 | var _h = _vm.$createElement; 248 | 249 | var _c = _vm._self._c || _h; 250 | 251 | return _c('textarea', _vm._b({ 252 | directives: [{ 253 | name: "model", 254 | rawName: "v-model", 255 | value: _vm.value, 256 | expression: "value" 257 | }], 258 | domProps: { 259 | "value": _vm.value 260 | }, 261 | on: { 262 | "input": function input($event) { 263 | if ($event.target.composing) { 264 | return; 265 | } 266 | 267 | _vm.value = $event.target.value; 268 | } 269 | } 270 | }, 'textarea', _vm.attributes, false)); 271 | }, 272 | staticRenderFns: [], 273 | "extends": Field 274 | }; 275 | 276 | var FieldRadio = { 277 | render: function render() { 278 | var _vm = this; 279 | 280 | var _h = _vm.$createElement; 281 | 282 | var _c = _vm._self._c || _h; 283 | 284 | return _c('div', [_vm._l(_vm.filterOptions(_vm.options), function (option) { 285 | return [_c('input', _vm._b({ 286 | directives: [{ 287 | name: "model", 288 | rawName: "v-model", 289 | value: _vm.value, 290 | expression: "value" 291 | }], 292 | attrs: { 293 | "name": _vm.name, 294 | "type": "radio" 295 | }, 296 | domProps: { 297 | "value": option.value, 298 | "checked": _vm._q(_vm.value, option.value) 299 | }, 300 | on: { 301 | "change": function change($event) { 302 | _vm.value = option.value; 303 | } 304 | } 305 | }, 'input', _vm.attributes, false)), _vm._v(" "), _c('label', [_vm._v(_vm._s(option.text))])]; 306 | })], 2); 307 | }, 308 | staticRenderFns: [], 309 | "extends": Field 310 | }; 311 | 312 | var FieldCheckbox = { 313 | render: function render() { 314 | var _vm = this; 315 | 316 | var _h = _vm.$createElement; 317 | 318 | var _c = _vm._self._c || _h; 319 | 320 | return _c('input', _vm._b({ 321 | directives: [{ 322 | name: "model", 323 | rawName: "v-model", 324 | value: _vm.value, 325 | expression: "value" 326 | }], 327 | attrs: { 328 | "type": "checkbox" 329 | }, 330 | domProps: { 331 | "checked": Array.isArray(_vm.value) ? _vm._i(_vm.value, null) > -1 : _vm.value 332 | }, 333 | on: { 334 | "change": function change($event) { 335 | var $$a = _vm.value, 336 | $$el = $event.target, 337 | $$c = $$el.checked ? true : false; 338 | 339 | if (Array.isArray($$a)) { 340 | var $$v = null, 341 | $$i = _vm._i($$a, $$v); 342 | 343 | if ($$el.checked) { 344 | $$i < 0 && (_vm.value = $$a.concat([$$v])); 345 | } else { 346 | $$i > -1 && (_vm.value = $$a.slice(0, $$i).concat($$a.slice($$i + 1))); 347 | } 348 | } else { 349 | _vm.value = $$c; 350 | } 351 | } 352 | } 353 | }, 'input', _vm.attributes, false)); 354 | }, 355 | staticRenderFns: [], 356 | "extends": Field 357 | }; 358 | 359 | var FieldSelect = { 360 | render: function render() { 361 | var _vm = this; 362 | 363 | var _h = _vm.$createElement; 364 | 365 | var _c = _vm._self._c || _h; 366 | 367 | return _c('select', _vm._b({ 368 | directives: [{ 369 | name: "model", 370 | rawName: "v-model", 371 | value: _vm.value, 372 | expression: "value" 373 | }], 374 | on: { 375 | "change": function change($event) { 376 | var $$selectedVal = Array.prototype.filter.call($event.target.options, function (o) { 377 | return o.selected; 378 | }).map(function (o) { 379 | var val = "_value" in o ? o._value : o.value; 380 | return val; 381 | }); 382 | _vm.value = $event.target.multiple ? $$selectedVal : $$selectedVal[0]; 383 | } 384 | } 385 | }, 'select', _vm.attributes, false), [_vm._l(_vm.filterOptions(_vm.options), function (option) { 386 | return [option.label ? _c('optgroup', { 387 | attrs: { 388 | "label": option.label 389 | } 390 | }, _vm._l(option.options, function (opt) { 391 | return _c('option', { 392 | domProps: { 393 | "value": opt.value 394 | } 395 | }, [_vm._v(_vm._s(opt.text))]); 396 | }), 0) : _c('option', { 397 | domProps: { 398 | "value": option.value 399 | } 400 | }, [_vm._v(_vm._s(option.text))])]; 401 | })], 2); 402 | }, 403 | staticRenderFns: [], 404 | "extends": Field 405 | }; 406 | 407 | var FieldRange = { 408 | render: function render() { 409 | var _vm = this; 410 | 411 | var _h = _vm.$createElement; 412 | 413 | var _c = _vm._self._c || _h; 414 | 415 | return _c('input', _vm._b({ 416 | directives: [{ 417 | name: "model", 418 | rawName: "v-model", 419 | value: _vm.value, 420 | expression: "value" 421 | }], 422 | attrs: { 423 | "type": "range" 424 | }, 425 | domProps: { 426 | "value": _vm.value 427 | }, 428 | on: { 429 | "__r": function __r($event) { 430 | _vm.value = $event.target.value; 431 | } 432 | } 433 | }, 'input', _vm.attributes, false)); 434 | }, 435 | staticRenderFns: [], 436 | "extends": Field 437 | }; 438 | 439 | var FieldNumber = { 440 | render: function render() { 441 | var _vm = this; 442 | 443 | var _h = _vm.$createElement; 444 | 445 | var _c = _vm._self._c || _h; 446 | 447 | return _c('input', _vm._b({ 448 | directives: [{ 449 | name: "model", 450 | rawName: "v-model", 451 | value: _vm.value, 452 | expression: "value" 453 | }], 454 | attrs: { 455 | "type": "number" 456 | }, 457 | domProps: { 458 | "value": _vm.value 459 | }, 460 | on: { 461 | "input": function input($event) { 462 | if ($event.target.composing) { 463 | return; 464 | } 465 | 466 | _vm.value = $event.target.value; 467 | } 468 | } 469 | }, 'input', _vm.attributes, false)); 470 | }, 471 | staticRenderFns: [], 472 | "extends": Field 473 | }; 474 | 475 | var Fields = { 476 | render: function render() { 477 | var _vm = this; 478 | 479 | var _h = _vm.$createElement; 480 | 481 | var _c = _vm._self._c || _h; 482 | 483 | return _c('div', _vm._l(_vm.fields, function (field) { 484 | return _c('div', { 485 | directives: [{ 486 | name: "show", 487 | rawName: "v-show", 488 | value: _vm.evaluate(field.show), 489 | expression: "evaluate(field.show)" 490 | }], 491 | key: field.name 492 | }, [field.type != 'checkbox' ? _c('label', [_vm._v(_vm._s(field.label))]) : _vm._e(), _vm._v(" "), _c(field.component, { 493 | tag: "component", 494 | attrs: { 495 | "field": field, 496 | "values": _vm.values 497 | }, 498 | on: { 499 | "change": _vm.change 500 | } 501 | })], 1); 502 | }), 0); 503 | }, 504 | staticRenderFns: [], 505 | components: { 506 | FieldText: FieldText, 507 | FieldTextarea: FieldTextarea, 508 | FieldRadio: FieldRadio, 509 | FieldCheckbox: FieldCheckbox, 510 | FieldSelect: FieldSelect, 511 | FieldRange: FieldRange, 512 | FieldNumber: FieldNumber 513 | }, 514 | provide: function provide() { 515 | return { 516 | Fields: this 517 | }; 518 | }, 519 | props: { 520 | config: { 521 | type: [Object, Array], 522 | "default": function _default() { 523 | return {}; 524 | } 525 | }, 526 | values: { 527 | type: Object, 528 | "default": function _default() { 529 | return {}; 530 | } 531 | }, 532 | prefix: { 533 | type: String, 534 | "default": 'field-' 535 | } 536 | }, 537 | computed: { 538 | fields: function fields() { 539 | return this.prepare(); 540 | } 541 | }, 542 | methods: { 543 | change: function change(value, field) { 544 | set(this.values, field.name, value); 545 | this.$emit('change', value, field); 546 | }, 547 | prepare: function prepare(config, prefix) { 548 | if (config === void 0) { 549 | config = this.config; 550 | } 551 | 552 | if (prefix === void 0) { 553 | prefix = this.prefix; 554 | } 555 | 556 | var arr = isArray(config), 557 | fields = []; 558 | each(config, function (field, key) { 559 | field = assign({}, field); 560 | 561 | if (!field.name && !arr) { 562 | field.name = key; 563 | } 564 | 565 | if (field.name) { 566 | if (!field.type) { 567 | field.type = 'text'; 568 | } 569 | 570 | if (!field.component) { 571 | field.component = prefix + field.type; 572 | } 573 | 574 | fields.push(field); 575 | } else { 576 | warn("Field name missing " + JSON.stringify(field)); 577 | } 578 | }); 579 | return fields; 580 | }, 581 | evaluate: function evaluate(expression, values) { 582 | if (values === void 0) { 583 | values = this.values; 584 | } 585 | 586 | try { 587 | if (isUndefined(expression)) { 588 | return true; 589 | } 590 | 591 | if (isString(expression)) { 592 | expression = parse(expression); 593 | } 594 | 595 | if (isFunction(expression)) { 596 | return expression.call(this, values, { 597 | $match: $match, 598 | $get: function $get(key) { 599 | return get(values, key); 600 | } 601 | }); 602 | } 603 | 604 | return expression; 605 | } catch (e) { 606 | warn(e); 607 | } 608 | 609 | return true; 610 | } 611 | } 612 | }; 613 | 614 | function $match(subject, pattern, flags) { 615 | return subject && new RegExp(pattern, flags).test(subject); 616 | } 617 | 618 | /** 619 | * Install plugin. 620 | */ 621 | var Plugin = { 622 | Field: Field, 623 | Fields: Fields, 624 | install: function install(Vue) { 625 | if (this.installed) { 626 | return; 627 | } 628 | 629 | Util(Vue); 630 | log(this.version); 631 | Vue.component('field', Field); 632 | Vue.component('fields', Fields); 633 | }, 634 | version: '1.1.3' 635 | }; 636 | 637 | if (typeof window !== 'undefined' && window.Vue) { 638 | window.Vue.use(Plugin); 639 | } 640 | 641 | module.exports = Plugin; 642 | -------------------------------------------------------------------------------- /dist/vue-fields.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vue-fields v1.1.3 3 | * https://github.com/pagekit/vue-fields 4 | * Released under the MIT License. 5 | */ 6 | 7 | (function (global, factory) { 8 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : 9 | typeof define === 'function' && define.amd ? define(factory) : 10 | (global = global || self, global.VueFields = factory()); 11 | }(this, function () { 'use strict'; 12 | 13 | /** 14 | * Utility functions. 15 | */ 16 | var _config = {}, 17 | _set; 18 | 19 | var assign = Object.assign || _assign; 20 | var isArray = Array.isArray; 21 | function Util (_ref) { 22 | var set = _ref.set, 23 | config = _ref.config; 24 | _set = set; 25 | _config = config; 26 | } 27 | function log(message, color) { 28 | if (color === void 0) { 29 | color = '#41B883'; 30 | } 31 | 32 | if (typeof console !== 'undefined' && _config.devtools) { 33 | console.log("%c vue-fields %c " + message + " ", 'color: #fff; background: #35495E; padding: 1px; border-radius: 3px 0 0 3px;', "color: #fff; background: " + color + "; padding: 1px; border-radius: 0 3px 3px 0;"); 34 | } 35 | } 36 | function warn(message, color) { 37 | if (color === void 0) { 38 | color = '#DB6B00'; 39 | } 40 | 41 | log(message, color); 42 | } 43 | function isObject(obj) { 44 | return obj !== null && typeof obj === 'object'; 45 | } 46 | function isString(val) { 47 | return typeof val === 'string'; 48 | } 49 | function isFunction(val) { 50 | return typeof val === 'function'; 51 | } 52 | function isUndefined(val) { 53 | return typeof val === 'undefined'; 54 | } 55 | function get(obj, key, def) { 56 | var parts = isArray(key) ? key : key.split('.'); 57 | 58 | for (var i = 0; i < parts.length; i++) { 59 | if (isObject(obj) && !isUndefined(obj[parts[i]])) { 60 | obj = obj[parts[i]]; 61 | } else { 62 | return def; 63 | } 64 | } 65 | 66 | return obj; 67 | } 68 | function set(obj, key, val) { 69 | var parts = isArray(key) ? key : key.split('.'); 70 | 71 | while (parts.length > 1) { 72 | var part = parts.shift(); 73 | 74 | if (!isObject(obj[part])) { 75 | _set(obj, part, {}); 76 | } 77 | 78 | obj = obj[part]; 79 | } 80 | 81 | _set(obj, parts.shift(), val); 82 | } 83 | var parsedFunc = {}; 84 | var expressionRe = /((?:\d|true|false|null|undefined|(?:this\.|\$)[\w.$]+|\W)*)([\w][\w.-]*)?/g; 85 | var quotedStringRe = /([^"']+)((.)(?:[^\3\\]|\\.)*?\3|.)?/g; 86 | function parse(expr) { 87 | return parsedFunc[expr] = parsedFunc[expr] || Function('$values', '$context', "with($context){return " + expr.replace(quotedStringRe, function (match, unquoted, quoted) { 88 | if (quoted === void 0) { 89 | quoted = ''; 90 | } 91 | 92 | return unquoted.replace(expressionRe, function (match, prefix, expression) { 93 | if (prefix === void 0) { 94 | prefix = ''; 95 | } 96 | 97 | return match ? "" + prefix + (expression ? "$get('" + expression + "')" : '') : ''; 98 | }) + quoted; 99 | }) + "}"); 100 | } 101 | function each(obj, iterator) { 102 | var i, key; 103 | 104 | if (typeof obj.length == 'number') { 105 | for (i = 0; i < obj.length; i++) { 106 | iterator.call(obj[i], obj[i], i); 107 | } 108 | } else if (isObject(obj)) { 109 | for (key in obj) { 110 | if (obj.hasOwnProperty(key)) { 111 | iterator.call(obj[key], obj[key], key); 112 | } 113 | } 114 | } 115 | 116 | return obj; 117 | } 118 | /** 119 | * Object.assign() polyfill. 120 | */ 121 | 122 | function _assign(target) { 123 | for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 124 | sources[_key - 1] = arguments[_key]; 125 | } 126 | 127 | sources.forEach(function (source) { 128 | Object.keys(source || {}).forEach(function (key) { 129 | return target[key] = source[key]; 130 | }); 131 | }); 132 | return target; 133 | } 134 | 135 | var Field = { 136 | inject: ['Fields'], 137 | props: { 138 | field: { 139 | type: Object, 140 | required: true 141 | }, 142 | values: { 143 | type: Object, 144 | required: true 145 | } 146 | }, 147 | data: function data() { 148 | return assign({ 149 | name: '', 150 | label: '', 151 | attrs: {}, 152 | options: [], 153 | "default": undefined 154 | }, this.field); 155 | }, 156 | computed: { 157 | value: { 158 | get: function get$$1() { 159 | return get(this.values, this.name); 160 | }, 161 | set: function set$$1(value) { 162 | this.$emit('change', value, this); 163 | } 164 | }, 165 | attributes: { 166 | get: function get$$1() { 167 | if (!this.Fields.evaluate(this.enable)) { 168 | return assign({ 169 | disabled: 'true' 170 | }, this.attrs); 171 | } 172 | 173 | return this.attrs; 174 | } 175 | } 176 | }, 177 | created: function created() { 178 | if (isUndefined(this.value) && !isUndefined(this["default"])) { 179 | this.value = this["default"]; 180 | } 181 | }, 182 | methods: { 183 | filterOptions: function filterOptions(options) { 184 | var _this = this; 185 | 186 | var opts = []; 187 | 188 | if (!options) { 189 | warn("Invalid options provided for " + this.name); 190 | return opts; 191 | } 192 | 193 | each(options, function (value, name) { 194 | if (isObject(value)) { 195 | opts.push({ 196 | label: name, 197 | options: _this.filterOptions(value) 198 | }); 199 | } else { 200 | opts.push({ 201 | text: name, 202 | value: value 203 | }); 204 | } 205 | }); 206 | return opts; 207 | } 208 | } 209 | }; 210 | 211 | var FieldText = { 212 | render: function render() { 213 | var _vm = this; 214 | 215 | var _h = _vm.$createElement; 216 | 217 | var _c = _vm._self._c || _h; 218 | 219 | return _c('input', _vm._b({ 220 | directives: [{ 221 | name: "model", 222 | rawName: "v-model", 223 | value: _vm.value, 224 | expression: "value" 225 | }], 226 | attrs: { 227 | "type": "text" 228 | }, 229 | domProps: { 230 | "value": _vm.value 231 | }, 232 | on: { 233 | "input": function input($event) { 234 | if ($event.target.composing) { 235 | return; 236 | } 237 | 238 | _vm.value = $event.target.value; 239 | } 240 | } 241 | }, 'input', _vm.attributes, false)); 242 | }, 243 | staticRenderFns: [], 244 | "extends": Field 245 | }; 246 | 247 | var FieldTextarea = { 248 | render: function render() { 249 | var _vm = this; 250 | 251 | var _h = _vm.$createElement; 252 | 253 | var _c = _vm._self._c || _h; 254 | 255 | return _c('textarea', _vm._b({ 256 | directives: [{ 257 | name: "model", 258 | rawName: "v-model", 259 | value: _vm.value, 260 | expression: "value" 261 | }], 262 | domProps: { 263 | "value": _vm.value 264 | }, 265 | on: { 266 | "input": function input($event) { 267 | if ($event.target.composing) { 268 | return; 269 | } 270 | 271 | _vm.value = $event.target.value; 272 | } 273 | } 274 | }, 'textarea', _vm.attributes, false)); 275 | }, 276 | staticRenderFns: [], 277 | "extends": Field 278 | }; 279 | 280 | var FieldRadio = { 281 | render: function render() { 282 | var _vm = this; 283 | 284 | var _h = _vm.$createElement; 285 | 286 | var _c = _vm._self._c || _h; 287 | 288 | return _c('div', [_vm._l(_vm.filterOptions(_vm.options), function (option) { 289 | return [_c('input', _vm._b({ 290 | directives: [{ 291 | name: "model", 292 | rawName: "v-model", 293 | value: _vm.value, 294 | expression: "value" 295 | }], 296 | attrs: { 297 | "name": _vm.name, 298 | "type": "radio" 299 | }, 300 | domProps: { 301 | "value": option.value, 302 | "checked": _vm._q(_vm.value, option.value) 303 | }, 304 | on: { 305 | "change": function change($event) { 306 | _vm.value = option.value; 307 | } 308 | } 309 | }, 'input', _vm.attributes, false)), _vm._v(" "), _c('label', [_vm._v(_vm._s(option.text))])]; 310 | })], 2); 311 | }, 312 | staticRenderFns: [], 313 | "extends": Field 314 | }; 315 | 316 | var FieldCheckbox = { 317 | render: function render() { 318 | var _vm = this; 319 | 320 | var _h = _vm.$createElement; 321 | 322 | var _c = _vm._self._c || _h; 323 | 324 | return _c('input', _vm._b({ 325 | directives: [{ 326 | name: "model", 327 | rawName: "v-model", 328 | value: _vm.value, 329 | expression: "value" 330 | }], 331 | attrs: { 332 | "type": "checkbox" 333 | }, 334 | domProps: { 335 | "checked": Array.isArray(_vm.value) ? _vm._i(_vm.value, null) > -1 : _vm.value 336 | }, 337 | on: { 338 | "change": function change($event) { 339 | var $$a = _vm.value, 340 | $$el = $event.target, 341 | $$c = $$el.checked ? true : false; 342 | 343 | if (Array.isArray($$a)) { 344 | var $$v = null, 345 | $$i = _vm._i($$a, $$v); 346 | 347 | if ($$el.checked) { 348 | $$i < 0 && (_vm.value = $$a.concat([$$v])); 349 | } else { 350 | $$i > -1 && (_vm.value = $$a.slice(0, $$i).concat($$a.slice($$i + 1))); 351 | } 352 | } else { 353 | _vm.value = $$c; 354 | } 355 | } 356 | } 357 | }, 'input', _vm.attributes, false)); 358 | }, 359 | staticRenderFns: [], 360 | "extends": Field 361 | }; 362 | 363 | var FieldSelect = { 364 | render: function render() { 365 | var _vm = this; 366 | 367 | var _h = _vm.$createElement; 368 | 369 | var _c = _vm._self._c || _h; 370 | 371 | return _c('select', _vm._b({ 372 | directives: [{ 373 | name: "model", 374 | rawName: "v-model", 375 | value: _vm.value, 376 | expression: "value" 377 | }], 378 | on: { 379 | "change": function change($event) { 380 | var $$selectedVal = Array.prototype.filter.call($event.target.options, function (o) { 381 | return o.selected; 382 | }).map(function (o) { 383 | var val = "_value" in o ? o._value : o.value; 384 | return val; 385 | }); 386 | _vm.value = $event.target.multiple ? $$selectedVal : $$selectedVal[0]; 387 | } 388 | } 389 | }, 'select', _vm.attributes, false), [_vm._l(_vm.filterOptions(_vm.options), function (option) { 390 | return [option.label ? _c('optgroup', { 391 | attrs: { 392 | "label": option.label 393 | } 394 | }, _vm._l(option.options, function (opt) { 395 | return _c('option', { 396 | domProps: { 397 | "value": opt.value 398 | } 399 | }, [_vm._v(_vm._s(opt.text))]); 400 | }), 0) : _c('option', { 401 | domProps: { 402 | "value": option.value 403 | } 404 | }, [_vm._v(_vm._s(option.text))])]; 405 | })], 2); 406 | }, 407 | staticRenderFns: [], 408 | "extends": Field 409 | }; 410 | 411 | var FieldRange = { 412 | render: function render() { 413 | var _vm = this; 414 | 415 | var _h = _vm.$createElement; 416 | 417 | var _c = _vm._self._c || _h; 418 | 419 | return _c('input', _vm._b({ 420 | directives: [{ 421 | name: "model", 422 | rawName: "v-model", 423 | value: _vm.value, 424 | expression: "value" 425 | }], 426 | attrs: { 427 | "type": "range" 428 | }, 429 | domProps: { 430 | "value": _vm.value 431 | }, 432 | on: { 433 | "__r": function __r($event) { 434 | _vm.value = $event.target.value; 435 | } 436 | } 437 | }, 'input', _vm.attributes, false)); 438 | }, 439 | staticRenderFns: [], 440 | "extends": Field 441 | }; 442 | 443 | var FieldNumber = { 444 | render: function render() { 445 | var _vm = this; 446 | 447 | var _h = _vm.$createElement; 448 | 449 | var _c = _vm._self._c || _h; 450 | 451 | return _c('input', _vm._b({ 452 | directives: [{ 453 | name: "model", 454 | rawName: "v-model", 455 | value: _vm.value, 456 | expression: "value" 457 | }], 458 | attrs: { 459 | "type": "number" 460 | }, 461 | domProps: { 462 | "value": _vm.value 463 | }, 464 | on: { 465 | "input": function input($event) { 466 | if ($event.target.composing) { 467 | return; 468 | } 469 | 470 | _vm.value = $event.target.value; 471 | } 472 | } 473 | }, 'input', _vm.attributes, false)); 474 | }, 475 | staticRenderFns: [], 476 | "extends": Field 477 | }; 478 | 479 | var Fields = { 480 | render: function render() { 481 | var _vm = this; 482 | 483 | var _h = _vm.$createElement; 484 | 485 | var _c = _vm._self._c || _h; 486 | 487 | return _c('div', _vm._l(_vm.fields, function (field) { 488 | return _c('div', { 489 | directives: [{ 490 | name: "show", 491 | rawName: "v-show", 492 | value: _vm.evaluate(field.show), 493 | expression: "evaluate(field.show)" 494 | }], 495 | key: field.name 496 | }, [field.type != 'checkbox' ? _c('label', [_vm._v(_vm._s(field.label))]) : _vm._e(), _vm._v(" "), _c(field.component, { 497 | tag: "component", 498 | attrs: { 499 | "field": field, 500 | "values": _vm.values 501 | }, 502 | on: { 503 | "change": _vm.change 504 | } 505 | })], 1); 506 | }), 0); 507 | }, 508 | staticRenderFns: [], 509 | components: { 510 | FieldText: FieldText, 511 | FieldTextarea: FieldTextarea, 512 | FieldRadio: FieldRadio, 513 | FieldCheckbox: FieldCheckbox, 514 | FieldSelect: FieldSelect, 515 | FieldRange: FieldRange, 516 | FieldNumber: FieldNumber 517 | }, 518 | provide: function provide() { 519 | return { 520 | Fields: this 521 | }; 522 | }, 523 | props: { 524 | config: { 525 | type: [Object, Array], 526 | "default": function _default() { 527 | return {}; 528 | } 529 | }, 530 | values: { 531 | type: Object, 532 | "default": function _default() { 533 | return {}; 534 | } 535 | }, 536 | prefix: { 537 | type: String, 538 | "default": 'field-' 539 | } 540 | }, 541 | computed: { 542 | fields: function fields() { 543 | return this.prepare(); 544 | } 545 | }, 546 | methods: { 547 | change: function change(value, field) { 548 | set(this.values, field.name, value); 549 | this.$emit('change', value, field); 550 | }, 551 | prepare: function prepare(config, prefix) { 552 | if (config === void 0) { 553 | config = this.config; 554 | } 555 | 556 | if (prefix === void 0) { 557 | prefix = this.prefix; 558 | } 559 | 560 | var arr = isArray(config), 561 | fields = []; 562 | each(config, function (field, key) { 563 | field = assign({}, field); 564 | 565 | if (!field.name && !arr) { 566 | field.name = key; 567 | } 568 | 569 | if (field.name) { 570 | if (!field.type) { 571 | field.type = 'text'; 572 | } 573 | 574 | if (!field.component) { 575 | field.component = prefix + field.type; 576 | } 577 | 578 | fields.push(field); 579 | } else { 580 | warn("Field name missing " + JSON.stringify(field)); 581 | } 582 | }); 583 | return fields; 584 | }, 585 | evaluate: function evaluate(expression, values) { 586 | if (values === void 0) { 587 | values = this.values; 588 | } 589 | 590 | try { 591 | if (isUndefined(expression)) { 592 | return true; 593 | } 594 | 595 | if (isString(expression)) { 596 | expression = parse(expression); 597 | } 598 | 599 | if (isFunction(expression)) { 600 | return expression.call(this, values, { 601 | $match: $match, 602 | $get: function $get(key) { 603 | return get(values, key); 604 | } 605 | }); 606 | } 607 | 608 | return expression; 609 | } catch (e) { 610 | warn(e); 611 | } 612 | 613 | return true; 614 | } 615 | } 616 | }; 617 | 618 | function $match(subject, pattern, flags) { 619 | return subject && new RegExp(pattern, flags).test(subject); 620 | } 621 | 622 | /** 623 | * Install plugin. 624 | */ 625 | var Plugin = { 626 | Field: Field, 627 | Fields: Fields, 628 | install: function install(Vue) { 629 | if (this.installed) { 630 | return; 631 | } 632 | 633 | Util(Vue); 634 | log(this.version); 635 | Vue.component('field', Field); 636 | Vue.component('fields', Fields); 637 | }, 638 | version: '1.1.3' 639 | }; 640 | 641 | if (typeof window !== 'undefined' && window.Vue) { 642 | window.Vue.use(Plugin); 643 | } 644 | 645 | return Plugin; 646 | 647 | })); 648 | --------------------------------------------------------------------------------