Skip to content

Commit

Permalink
Merge branch 'samples/fsfiddle-demo' into develop
Browse files Browse the repository at this point in the history
* samples/fsfiddle-demo:
  jsfiddle-sample embedded into repo
  migrated VFG docs to newer GitBooks, created GitHub Repo for Docs to allow for easier maintenance, updated JSFiddle to use "latest" VFG, and created a CodePen version as well
  Codacy (guard-for-in) fix
  fixed code structure
  added "options" to VFG install function, appending custom "validators" to the validators object that are passed into `Vue.use(VueFormGenerator, { validators: { key: (value, field, model) => {} })
  added an optional "unique" flag to "getFieldID" that appends lodash "uniqueId" to the ID when true.  Fixes vue-generators#468
  fixed single-quotes
  added "type" attribute to inside buttons schema, defaults to "button" when one is not provided
  fixes vue-generators#480 - dates are always passed to "date" and "datetime-local" elements using the standard format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss), and "datetime" elements are converted into "datetime-local" (datetime is deprecated/obsolete).
  added "item.disabled" logic, supporting both boolean values and a function that is passed a reference to the model to determine disabled logic based on the model.
  listen for model-updated from `fields`, and fix `debounceFormatFunction` property to match fieldInput's `debounceFormatFunc` instead.
  Fix required number input does not require a value
  • Loading branch information
zoul0813 committed Dec 14, 2018
2 parents fa0a2ff + 5d2620b commit 85f6e21
Show file tree
Hide file tree
Showing 14 changed files with 288 additions and 19 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ A schema-based form generator component for Vue.js.

## Demo

[JSFiddle simple example](https://jsfiddle.net/icebob/0mg1v81e/)
[JSFiddle simple example](https://jsfiddle.net/zoul0813/d8excp36/)
[CodePen simple example](https://codepen.io/zoul0813/pen/OrNVNw)

[![Screenshot](https://icebob.gitbooks.io/vueformgenerator/content/assets/vfg-example1.png)](https://jsfiddle.net/icebob/0mg1v81e/)
[![Screenshot](https://github.com/vue-generators/vue-form-generator-docs/raw/master/assets/vfg-example1.png)](https://jsfiddle.net/zoul0813/d8excp36/)

## Features

Expand All @@ -33,7 +34,7 @@ A schema-based form generator component for Vue.js.

## Documentation

[Online documentation on Gitbook](https://icebob.gitbooks.io/vueformgenerator/content/)
[Online documentation on Gitbook](https://vue-generators.gitbook.io/vue-generators/)

## Dependencies

Expand All @@ -43,7 +44,7 @@ While built-in fields don't need external dependencies, optional fields may need
These dependencies fall into two camps: jQuery or Vanilla. You can find almost the same functionality in both flavors.
In the end, it's your choice to depend on jQuery or not.

You can find details about dependencies in the official [documentation](https://icebob.gitbooks.io/vueformgenerator/content/) under each specific component.
You can find details about dependencies in the official [documentation](https://vue-generators.gitbook.io/vue-generators/) under each specific component.

## Installation

Expand Down
61 changes: 61 additions & 0 deletions examples/jsfiddle-sample/demo.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
html {
font-family: Tahoma;
font-size: 14px;
}

body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.42857143;
color: #333;
}

pre {
overflow: auto;
}
pre .string { color: #885800; }
pre .number { color: blue; }
pre .boolean { color: magenta; }
pre .null { color: red; }
pre .key { color: green; }

h1 {
text-align: center;
font-size: 36px;
margin-top: 20px;
margin-bottom: 10px;
font-weight: 500;
}

fieldset {
border: 0;
}

.panel {
margin-bottom: 20px;
background-color: #fff;
border: 1px solid transparent;
border-radius: 4px;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
border-color: #ddd;
}

.panel-heading {
color: #333;
background-color: #f5f5f5;
border-color: #ddd;

padding: 10px 15px;
border-bottom: 1px solid transparent;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}

.panel-body {
padding: 15px;
}

.field-checklist .wrapper {
width: 100%;
}
13 changes: 13 additions & 0 deletions examples/jsfiddle-sample/demo.details
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
name: vue-form-generator example
description: https://github.com/vue-generators/vue-form-generator
authors:
- David Higgins (@zoul0813)
- Icebob (@icebob)
resources:
- https://unpkg.com/[email protected]/dist/vue.min.js
- https://unpkg.com/vue-form-generator
- https://unpkg.com/vue-form-generator/dist/vfg.css
normalize_css: no
load_type: l
...
23 changes: 23 additions & 0 deletions examples/jsfiddle-sample/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<h1 class="text-center">Demo of vue-form-generator</h1>
<div class="container" id="app">
<div class="panel panel-default">
<div class="panel-heading">Form</div>
<div class="panel-body">
<vue-form-generator :schema="schema" :model="model" :options="formOptions"></vue-form-generator>
</div>
</div>

<div class="panel panel-default">
<div class="panel-heading">Model</div>
<div class="panel-body">
<pre v-if="model" v-html="prettyJSON(model)"></pre>
</div>
</div>

<div class="panel panel-default">
<div class="panel-heading">Schema</div>
<div class="panel-body">
<pre v-if="model" v-html="prettyJSON(schema)"></pre>
</div>
</div>
</div>
114 changes: 114 additions & 0 deletions examples/jsfiddle-sample/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
var vm = new Vue({
el: "#app",

components: {
"vue-form-generator": VueFormGenerator.component
},

data() {
return {
model: {
id: 1,
name: "John Doe",
password: "J0hnD03!x4",
age: 35,
skills: ["Javascript", "VueJS"],
email: "[email protected]",
status: true
},
schema: {
fields: [{
type: "input",
inputType: "text",
label: "ID",
model: "id",
readonly: true,
featured: false,
disabled: true
}, {
type: "input",
inputType: "text",
label: "Name",
model: "name",
readonly: false,
featured: true,
required: true,
disabled: false,
placeholder: "User's name",
validator: VueFormGenerator.validators.string
}, {
type: "input",
inputType: "password",
label: "Password",
model: "password",
min: 6,
required: true,
hint: "Minimum 6 characters",
validator: VueFormGenerator.validators.string
}, {
type: "input",
inputType: "number",
label: "Age",
model: "age",
min: 18,
validator: VueFormGenerator.validators.number
}, {
type: "input",
inputType: "email",
label: "E-mail",
model: "email",
placeholder: "User's e-mail address",
validator: VueFormGenerator.validators.email
}, {
type: "checklist",
label: "Skills",
model: "skills",
multi: true,
required: true,
multiSelect: true,
values: ["HTML5", "Javascript", "CSS3", "CoffeeScript", "AngularJS", "ReactJS", "VueJS"]
}, {
type: "switch",
label: "Status",
model: "status",
multi: true,
readonly: false,
featured: false,
disabled: false,
default: true,
textOn: "Active",
textOff: "Inactive"
}]
},

formOptions: {
validateAfterLoad: true,
validateAfterChanged: true
}
};
},

methods: {
prettyJSON: function(json) {
if (json) {
json = JSON.stringify(json, undefined, 4);
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
var cls = 'number';
if (/^"/.test(match)) {
if (/:$/.test(match)) {
cls = 'key';
} else {
cls = 'string';
}
} else if (/true|false/.test(match)) {
cls = 'boolean';
} else if (/null/.test(match)) {
cls = 'null';
}
return '<span class="' + cls + '">' + match + '</span>';
});
}
}
},
});
8 changes: 4 additions & 4 deletions src/fields/abstractField.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { get as objGet, forEach, isFunction, isString, isArray, debounce } from "lodash";
import { get as objGet, forEach, isFunction, isString, isArray, debounce, uniqueId } from "lodash";
import validators from "../utils/validators";
import { slugifyFormID } from "../utils/schema";

Expand Down Expand Up @@ -31,7 +31,7 @@ export default {
return {
errors: [],
debouncedValidateFunc: null,
debouncedFormatFunction: null
debouncedFormatFunc: null
};
},

Expand Down Expand Up @@ -208,9 +208,9 @@ export default {
}
},

getFieldID(schema) {
getFieldID(schema, unique = false) {
const idPrefix = objGet(this.formOptions, "fieldIdPrefix", "");
return slugifyFormID(schema, idPrefix);
return slugifyFormID(schema, idPrefix) + (unique ? "-" + uniqueId() : "");
},

getFieldClasses() {
Expand Down
4 changes: 2 additions & 2 deletions src/fields/core/fieldChecklist.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
.listbox.form-control(v-if="schema.listBox", :disabled="disabled")
.list-row(v-for="item in items", :class="{'is-checked': isItemChecked(item)}")
label
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
input(:id="getFieldID(schema, true)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
| {{ getItemName(item) }}

.combobox.form-control(v-if="!schema.listBox", :disabled="disabled")
Expand All @@ -14,7 +14,7 @@
.dropList
.list-row(v-if="comboExpanded", v-for="item in items", :class="{'is-checked': isItemChecked(item)}")
label
input(:id="getFieldID(schema)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
input(:id="getFieldID(schema, true)", type="checkbox", :checked="isItemChecked(item)", :disabled="disabled", @change="onChanged($event, item)", :name="getInputName(item)", v-attributes="'input'")
| {{ getItemName(item) }}
</template>

Expand Down
32 changes: 31 additions & 1 deletion src/fields/core/fieldInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
.wrapper(v-attributes="'wrapper'")
input.form-control(
:id="getFieldID(schema)",
:type="schema.inputType.toLowerCase()",
:type="inputType",
:value="value",
@input="onInput",
@blur="onBlur",
Expand Down Expand Up @@ -53,6 +53,16 @@ const DATETIME_FORMATS = {
export default {
mixins: [abstractField],
computed: {
inputType() {
if(this.schema && this.schema.inputType === "datetime") {
// convert "datetime" to "datetime-local" (datetime deprecated in favor of "datetime-local")
// ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime
return "datetime-local";
}
return this.schema.inputType;
}
},
methods: {
formatValueToModel(value) {
if (value != null) {
Expand All @@ -71,6 +81,15 @@ export default {
return value;
},
formatValueToField(value) {
switch(this.schema.inputType.toLowerCase()) {
case "date":
case "datetime":
case "datetime-local":
return this.formatDatetimeValueToField(value);
}
return value;
},
formatDatetimeToModel(newValue, oldValue) {
let defaultFormat = DATETIME_FORMATS[this.schema.inputType.toLowerCase()];
let m = fecha.parse(newValue, defaultFormat);
Expand All @@ -83,6 +102,17 @@ export default {
}
this.updateModelValue(newValue, oldValue);
},
formatDatetimeValueToField(value) {
let defaultFormat = DATETIME_FORMATS[this.schema.inputType.toLowerCase()];
let m = value;
if(!isNumber(value)) {
m = fecha.parse(value, defaultFormat);
}
if(m !== false) {
return fecha.format(m, defaultFormat);
}
return value;
},
formatNumberToModel(newValue, oldValue) {
if (!isNumber(newValue)) {
newValue = NaN;
Expand Down
14 changes: 12 additions & 2 deletions src/fields/core/fieldRadios.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<template lang="pug">
.radio-list(:disabled="disabled", v-attributes="'wrapper'")
label(v-for="item in items", :class="{'is-checked': isItemChecked(item)}", v-attributes="'label'")
input(:id="getFieldID(schema)", type="radio", :disabled="disabled", :name="id", @click="onSelection(item)", :value="getItemValue(item)", :checked="isItemChecked(item)", :class="schema.fieldClasses", :required="schema.required", v-attributes="'input'")
input(:id="getFieldID(schema, true)", type="radio", :disabled="isItemDisabled(item)", :name="id", @click="onSelection(item)", :value="getItemValue(item)", :checked="isItemChecked(item)", :class="schema.fieldClasses", :required="schema.required", v-attributes="'input'")
| {{ getItemName(item) }}

</template>

<script>
import { isObject } from "lodash";
import { isObject, isFunction, get as objGet } from "lodash";
import abstractField from "../abstractField";
export default {
Expand Down Expand Up @@ -64,6 +64,16 @@ export default {
isItemChecked(item) {
let currentValue = this.getItemValue(item);
return currentValue === this.value;
},
isItemDisabled(item) {
if (this.disabled) {
return true;
}
let disabled = objGet(item, "disabled", false);
if (isFunction(disabled)) {
return disabled(this.model);
}
return disabled;
}
}
};
Expand Down
2 changes: 1 addition & 1 deletion src/formGenerator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
div.vue-form-generator(v-if='schema != null')
fieldset(v-if="schema.fields", :is='tag')
template(v-for='field in fields')
form-group(v-if='fieldVisible(field)', :vfg="vfg", :field="field", :errors="errors", :model="model", :options="options", @validated="onFieldValidated")
form-group(v-if='fieldVisible(field)', :vfg="vfg", :field="field", :errors="errors", :model="model", :options="options", @validated="onFieldValidated", @model-updated="onModelUpdated")

template(v-for='group in groups')
fieldset(:is='tag', :class='getFieldRowClasses(group)')
Expand Down
Loading

0 comments on commit 85f6e21

Please sign in to comment.