406 lines
12 KiB
JavaScript
406 lines
12 KiB
JavaScript
//FastVue.Form
|
|
(function (Form, $) {
|
|
|
|
"use strict";
|
|
|
|
Form.fields = {};
|
|
Form.renders = {};
|
|
|
|
function initForm(Form) {
|
|
|
|
var _fields = [];
|
|
|
|
//销毁字段
|
|
function __destroyField(f) {
|
|
if (!f.view.el) return;
|
|
this.view.el = f.view.el;
|
|
f.destroyed && f.destroyed.call(this);
|
|
f.view.el.remove();
|
|
f.view.el = null;
|
|
}
|
|
|
|
//初始化字段
|
|
function __initFields(ctx, opts) {
|
|
|
|
!opts.preId && (opts.preId = "fv");
|
|
|
|
let results = [], layout = ctx.layout('input'), data = ctx.data;
|
|
|
|
for (let [pname, field] of Object.entries(opts.fields)) {
|
|
|
|
!field.name && (field.name = pname);
|
|
|
|
if (field.name in data) {
|
|
field.value = data[field.name];
|
|
} else {
|
|
data[field.name] = field.value;
|
|
}
|
|
|
|
!field.type && (field.type = 'text');
|
|
|
|
!field.id && (field.id = opts.preId + pname);
|
|
|
|
field = FastVue.extend(true, {}, layout, field);
|
|
|
|
let constructor = Form.fields[field.type] || Form.Field;
|
|
field = new constructor(field);
|
|
field.onchange = field.onchange.bind(ctx);
|
|
|
|
//可能存在多个name相同的field
|
|
if (field.name in ctx.fields) {
|
|
ctx.fields[field.name].push(field);
|
|
} else {
|
|
ctx.fields[field.name] = [field];
|
|
}
|
|
|
|
results.push(field);
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
//初始化Form
|
|
Form.prototype.init = function (opts) {
|
|
|
|
if (!opts) return;
|
|
|
|
//init dom root
|
|
let domRoot = document.getElementById(opts.el.substring(1));
|
|
if (!domRoot) throw '[FastVue.Form]el not found:' + opts.el;
|
|
|
|
//init data
|
|
if (opts.data) {
|
|
Object.assign(this.data, opts.data);
|
|
}
|
|
|
|
//init layout
|
|
let layout = FastVue.extend(true, this.layout, opts.layout);
|
|
!layout.display && (layout.display = 'inline');
|
|
!layout.cssClass && (layout.display = '');
|
|
!layout.title && (layout.title = {});
|
|
|
|
//init fields
|
|
let fields = __initFields(opts);
|
|
|
|
//render fields
|
|
Form.render(this, domRoot, fields);
|
|
|
|
let self = this;
|
|
|
|
fields.forEach(f => {
|
|
self.view.el = f.view.el;
|
|
f.created && f.created.call(self);
|
|
});
|
|
};
|
|
|
|
Form.prototype.set = function (name, newVal, byInput) {
|
|
var oldVal = this.data[name];
|
|
this.data[name] = newVal;
|
|
var fs = this.fields[name];
|
|
fs && fs.forEach(f => {
|
|
if (f.view.visible !== false && f.onchange && f.view.el) {
|
|
var oldVal = f.view.el.value;
|
|
f.view.el.value = value;
|
|
f.onchange(f.view.el, value, oldVal, false);
|
|
}
|
|
});
|
|
};
|
|
}
|
|
|
|
initForm(Form);
|
|
|
|
}(FastVue.Form));
|
|
|
|
//Form-render
|
|
(function (Form, $) {
|
|
|
|
function __readonly(field) {
|
|
let props = {
|
|
type: 'hidden', name: field.name, id: field.id,
|
|
value: field.value, required: !!field.required
|
|
};
|
|
let input = Object.assign(document.createElement('input'), props);
|
|
|
|
let div = document.createElement('div');
|
|
div.className = 'readonly';
|
|
div.innerHTML = '<span>' + field.value + '</span>';
|
|
field.width && FastVue.setWidth(div, field.width);
|
|
|
|
return div.append(input) || div;
|
|
}
|
|
|
|
function __field(field) {
|
|
if (field.type === 'hidden') {
|
|
return;
|
|
}
|
|
|
|
var type = typeof field.visible;
|
|
if (type !== "undefined" && (type === 'function' && !field.visible.call(this.context) || !field.visible)) {
|
|
field.$visible = false;
|
|
return;
|
|
}
|
|
|
|
let domDiv = document.createElement('div');
|
|
|
|
domDiv.className = 'form-group';
|
|
|
|
let domTitle = Object.assign(document.createElement('label'), {
|
|
className: this.titleLayout.cssClass || '', innerText: field.title
|
|
});
|
|
|
|
this.titleLayout.width && FastVue.setWidth(domTitle, this.titleLayout.width);
|
|
|
|
let domInput;
|
|
if (field.readonly) {
|
|
domInput = __readonly(field);
|
|
} else {
|
|
domInput = field.$create(this.context);
|
|
if (domInput.parentElement) {
|
|
while (domInput.parentElement) {
|
|
domInput = domInput.parentElement;
|
|
}
|
|
} else {
|
|
let temp = domInput;
|
|
domInput = document.createElement('div');
|
|
domInput.append(temp);
|
|
}
|
|
}
|
|
|
|
domDiv.append(domTitle) || domDiv.append(domInput) || this.domForm.append(domDiv);
|
|
}
|
|
|
|
function render(domRoot, fields) {
|
|
let domForm = Object.assign(document.createElement('form'), {
|
|
autocomplete: "off",
|
|
className: "form-" + (this.$layout.display || "inline") + ' ' + (this.$layout.cssClass || '')
|
|
});
|
|
let func = __field.bind({ context: this, domForm: domForm, titleLayout: layout.title });
|
|
fields.forEach(f => func(f));
|
|
domRoot.append(domForm);
|
|
}
|
|
|
|
Form.render = render;
|
|
|
|
}(FastVue.Form));
|
|
|
|
//Form-Field
|
|
(function (Form, $) {
|
|
|
|
function Field(config) {
|
|
|
|
!this.title && (this.title = this.name);
|
|
|
|
this.$create = function () {
|
|
let span = document.createElement('span');
|
|
span.style.color = 'red';
|
|
span.innerText = '错误!!';
|
|
this.$el = span;
|
|
return span;
|
|
};
|
|
|
|
this.$onchange = function (ctx) {
|
|
let newVal = this.$el.value;
|
|
ctx.data[this.name] = newVal;
|
|
if (this.onchange) {
|
|
ctx.view.el = this.vue.el;
|
|
this.onchange.call(ctx, newVal, oldVal, true);
|
|
}
|
|
};
|
|
|
|
FastVue.extend(true, this, config);
|
|
}
|
|
|
|
Field.prototype = {
|
|
name: "",
|
|
title: "",
|
|
value: "",
|
|
cssClass: "",
|
|
visible: true,
|
|
readonly: false,
|
|
required: false,
|
|
format(value) { return value; },
|
|
unformat(value) { return value; },
|
|
onchange(oldVal, newVal) { },
|
|
created() { },
|
|
destroyed() { }
|
|
};
|
|
|
|
Object.freeze(Field);
|
|
|
|
Form.Field = Field;
|
|
|
|
}(FastVue.Form));
|
|
|
|
//Form-TextField
|
|
(function (Form) {
|
|
|
|
let Field = Form.Field;
|
|
|
|
//返回dom对象
|
|
function createAddon(context, domInput, groupOptions) {
|
|
|
|
//返回dom对象
|
|
function _create(addon, isPrepend) {
|
|
if (typeof addon === 'function') {
|
|
addon = addon.call(context);
|
|
}
|
|
let div = document.createElement('div');
|
|
div.className = isPrepend ? 'input-group-append' : 'input-group-append';
|
|
if (Array.isArray(addon)) {
|
|
div.innerHTML = addon.map(x => '<span class="input-group-text">' + x + '</span>').join("");
|
|
}
|
|
if (typeof addon === 'string') {
|
|
div.innerHTML = '<span class="input-group-text">' + addon + '</span>';
|
|
}
|
|
return div;
|
|
}
|
|
|
|
let groupFlag = (groupOptions.prepend ? 1 : 0) | (groupOptions.append ? 2 : 0);
|
|
|
|
if (groupFlag > 0) {
|
|
let inputGroup = document.createElement('div');
|
|
inputGroup.className = "input-group";
|
|
if (1 === (groupFlag & 1)) {
|
|
inputGroup.append(_create(groupOptions.prepend, true));
|
|
}
|
|
inputGroup.append(domInput);
|
|
if (2 === (groupFlag & 2)) {
|
|
inputGroup.append(_create(groupOptions.append, false));
|
|
}
|
|
inputGroup.style.width = domInput.style.width;
|
|
domInput.style.width = '';
|
|
return inputGroup;
|
|
}
|
|
}
|
|
|
|
function setAutoComplete(context, domInput) {
|
|
if (this.autocomplete === true) {
|
|
domInput.setAttribute("autocomplete", "on");
|
|
} else if (typeof this.autocomplete === "string") {
|
|
domInput.setAttribute("autocomplete", this.autocomplete);
|
|
} else if (typeof this.autocomplete === "object") {
|
|
let opts = this.autocomplete;
|
|
if (Array.isArray(this.autocomplete)) {
|
|
opts = {
|
|
lookup: this.autocomplete,
|
|
onSelect: onchange
|
|
};
|
|
} else {
|
|
opts = {
|
|
lookup: opts.items,
|
|
formatResult: opts.itemRender,
|
|
onSelect: onchange,
|
|
nameField: opts.nameField,
|
|
valueField: opts.valueField,
|
|
searchField: opts.searchField
|
|
};
|
|
}
|
|
FastVue.autocomplete(domInput, opts);
|
|
} else {
|
|
throw "[FastVue.Form]autocomplete unknown";
|
|
}
|
|
}
|
|
|
|
//返回dom对象
|
|
function create(context) {
|
|
|
|
let props = {
|
|
type: 'input', id: this.id, name: this.name, className: 'form-control ' + this.cssClass, autocomplete: "off",
|
|
value: this.value, placeholder: this.placeholder, readonly: !!this.readOnly, required: !!this.required
|
|
};
|
|
|
|
let domInput = Object.assign(document.createElement('input'), props);
|
|
|
|
this.width && FastVue.setWidth(domInput, this.width);
|
|
|
|
if (this.group) {
|
|
createAddon(context, domInput, this.group);
|
|
}
|
|
|
|
var onchange = this.$onchange.bind(this, context);
|
|
|
|
if (this.autocomplete) {
|
|
setAutoComplete.call(this, context, domInput);
|
|
} else {
|
|
domInput.addEventListener('change', onchange);
|
|
}
|
|
|
|
return this.$el = domInput;
|
|
}
|
|
|
|
function TextField(config) {
|
|
Field.call(this, config);
|
|
this.$checkFunction(['validate']);
|
|
this.$create = create;
|
|
}
|
|
|
|
TextField.prototype = new Field({
|
|
placeholder: '',
|
|
group: null,//{append:''|[]|function,prepend}
|
|
validate(value) { return ""; }
|
|
});
|
|
|
|
Object.freeze(TextField);
|
|
|
|
Form.fields.text = Form.TextField = TextField;
|
|
|
|
}(FastVue.Form));
|
|
|
|
//Form-SelectField
|
|
(function (Form) {
|
|
|
|
let Field = Form.Field;
|
|
|
|
//field.create,返回dom对象
|
|
function create(context) {
|
|
|
|
let props = {
|
|
id: this.id, name: this.name, className: 'form-control ' + this.cssClass,
|
|
value: this.value, placeholder: this.placeholder, required: !!this.required
|
|
};
|
|
|
|
let domSelect = Object.assign(document.createElement('select'), props);
|
|
|
|
this.width && FastVue.setWidth(domSelect, this.width);
|
|
|
|
domSelect.addEventListener('change', this.$onchange.bind(this, context));
|
|
|
|
let options = this.options;
|
|
if (options) {
|
|
if (typeof options === 'function') {
|
|
options = options.call(context.Proxy);
|
|
}
|
|
if (Array.isArray(options)) {
|
|
if (typeof options[0] === 'string') {
|
|
options = options.map(x => new Object({ value: x, text: x }));
|
|
}
|
|
options.forEach(function (item) {
|
|
let domOption = document.createElement('option');
|
|
domOption.setAttribute('value', item.value);
|
|
domOption.innerText = item.text;
|
|
domSelect.append(domOption);
|
|
});
|
|
} else {
|
|
throw '[SelectField.options]必须为数组或返回数组结果的函数';
|
|
}
|
|
}
|
|
|
|
return this.$el = domSelect;
|
|
}
|
|
|
|
function SelectField(config) {
|
|
Field.call(this, config);
|
|
this.$create = create;
|
|
}
|
|
|
|
SelectField.prototype = new Field({
|
|
options: []
|
|
});
|
|
|
|
Object.freeze(SelectField);
|
|
|
|
Form.fields.select = Form.SelectField = SelectField;
|
|
|
|
}(FastVue.Form));
|
|
|
|
Object.freeze(FastVue.Form); |