FormSchema 土著
基于 JSON Schema 和 原生 HTML 的 Vue 组件格式
目录
- 安装
- 演示
- 使用量
- 特征
- 支持的关键词
- 无关(被忽略)关键词
- 窗体化学式 API
- 与 Async Schema 合作
- 使用 Vue 路由器工作
- 与 JSON Schema $ref 指针合作
- 数据验证
- 标签翻译
- 渲染窗体元素
- 自定义窗体元素
- 描述界面
- 使用大小写
- 捐款
- 许可证
安装
npm install --save @formschema/native
演示

使用量
<template>
<FormSchema :schema="schema" v-model="model" @submit.prevent="submit">
<button type="submit">Subscribe</button>
</FormSchema>
</template>
<script>
import FormSchema from '@formschema/native'
import schema from './schema/newsletter-subscription.json'
export default {
data: () => ({
schema: schema,
model: {}
}),
methods: {
submit (e) {
// this.model contains the valid data according your JSON Schema.
// You can submit your model to the server here
}
},
components: { FormSchema }
}
</script>
特征
- 应用带布尔逻辑的子化学键
- 任何实例类型的验证关键字
表单Schema使用:- HTML 输入
text以图图type: 'string' - HTML 输入
number以图图type: 'number' | 'integer' - HTML 输入
hidden以图图type: 'null' - HTML 输入
checkbox以图图type: 'boolean'
- HTML 输入
- 数字实例关键词(数量和整数)
FormSchema 解析关键词maximum, (中文(简体) ),minimum, (中文(简体) ),exclusiveMaximum财务报告和审定财务报表exclusiveMinimum生成 HTML 属性max财务报告和审定财务报表min。 。 。 . - 字符串验证关键词
FormSchema 解析关键词maxLength, (中文(简体) ),minLength, (中文(简体) ),pattern生成 HTML 属性maxlength, (中文(简体) ),minlength财务报告和审定财务报表pattern。 。 。 . - 阵列的验证关键字
- 用"格式"进行语义验证
表单Schema使用:- HTML 输入
date以图图format: 'date' - HTML 输入
datetime-local以图图format: 'date-time' - HTML 输入
email以图图format: 'email' | 'idn-email' - HTML 输入
time以图图format: 'time' - HTML 输入
url以图图format: 'uri'
- HTML 输入
- 字符串编码非JSON数据
- 财产依赖和Schema依赖
- Schema 重新使用“ 定义 ” (见 JSON Schema $ref 指针(中文(简体) )
- Schema 说明
支持的关键词
- 类型 只有支持的字符串值。 不支持矩阵类型定义 .
- 语句 用于提供多个选项输入
- 上限, (中文(简体) ), 专有马克西姆, (中文(简体) ), 最低 财务报告和审定财务报表 最小 用于制取数值字段
- 倍数 用于渲染输入属性
step - 最大长度, (中文(简体) ), 分钟, (中文(简体) ), 模式 财务报告和审定财务报表 针头 用于渲染字符串字段
- 项目, (中文(简体) ), 额外 项目, (中文(简体) ), 最大项目, (中文(简体) ), 分钟项目 财务报告和审定财务报表 唯一项目 用于渲染数组字段
- 依赖关系 用于执行 财产依赖关系 财务报告和审定财务报表 Schema 依赖关系
- 内容编码
- 内容介质Type
- 何时
contentMediaType等于text/*, HTML 元素<textarea/>用于渲染 - 何时
contentMediaType不等同于text/*, HTML 元素<input/>有属性{ type: file, accept: contentMediaType }用于渲染
- 何时
- 标题 用于渲染输入标签
- 说明 用于提供输入描述
- 默认 用于定义默认输入值
- 仅读 用于将字段作为只读输入
无关(被忽略)关键词
由于FormSchema只是一个表单生成器,一些JSON Schema验证关键字 无关 :
窗体化学式 API
道具
| 名称 | 类型 | 说明 | 默认 |
|---|---|---|---|
schema 所需经费 | Object | 输入 JSON Schema 对象 . | |
v-model | any | 使用此指令来创建带有组件的双向数据绑定. 它会自动选择正确的方法来根据输入类型更新元素. | undefined |
id | String | 元素界面的id属性代表了窗体的标识符,反映了id全局属性. | Random unique ID |
name | String | 所出形式之名. 它必须是文件表格中独一无二的. | undefined |
bracketed-object-input-name | Boolean | 设定为 true (default),复选框输入和嵌入对象输入将 * 自动在名字结尾处加入括号(例如. name="grouped-checkbox-fields[]") (中文(简体) ). 设置此属性为 false,禁用此行为. | true |
search | Boolean | 使用此道具启用 search 用于查找网页、网站或网站收藏的网页的一栏. | false |
disabled | Boolean | 说明形式元素是否被禁用. | false |
components | ComponentsLib | 使用此道具覆盖带有自定义组件的默认本地 HTML 元素 . | GLOBAL.Elements |
descriptor | DescriptorInstance | UI Schema 描述器用于渲染. | {} |
validator | Function | 用于在发送数据前验证数据的验证器功能 input 活动.语法 function validator(field: GenericField): Promise<boolean>参数
回来的承诺 true 如果验证成功 false 否则 | null |
活动
| 名称 | 说明 |
|---|---|
input | 当元素值被改变时同步被点燃. 参数
|
方法
表单( )
获取 HTML 窗体对象引用 .
示例
<template>
<FormSchema ref="formSchema" :schema="schema"/>
</template>
<script>
import FormSchema from '@formschema/native'
export default {
components: { FormSchema },
data: () => ({
schema: { type: 'string' }
}),
mounted() {
console.log(this.$refs.formSchema.form())
}
};
</script>
语法
form(): HTMLFormElement | VNode | undefined
返回值
一个 HTMLFormElement 对象或一个 VNode 描述窗体元素的对象
对象,或 undefined 用于输入 JSON 计划对象.
与 Async Schema 合作
<template>
<FormSchema :schema="schema"/>
</template>
<script>
import axios from 'axios'
import FormSchema from '@formschema/native'
export default {
components: { FormSchema },
data: () => ({
schema: {}
}),
created() {
axios.get('/api/schema/subscription.json').then(({ data: schema }) => {
this.schema = schema
});
}
};
</script>
使用 Vue 路由器工作
装入同步计划 beforeRouterEnter 钩:
<template>
<FormSchema :schema="schema"/>
</template>
<script>
import axios from 'axios'
import FormSchema from '@formschema/native'
export default {
components: { FormSchema },
data: () => ({
schema: {}
}),
beforeRouterEnter(from, to, next) {
axios.get('/api/schema/subscription.json')
.then(({ data: schema }) => next((vm) => vm.setSchema(schema)))
.catch(next);
},
methods: {
setSchema(schema) {
this.schema = schema;
}
}
};
</script>
与 JSON Schema $ref 指针合作
用 JSON Schema 装入 $ref 指针,您需要安装额外的
解决这些困难的依赖性:
import $RefParser from 'json-schema-ref-parser';
import FormSchema from '@formschema/native';
import schemaWithPointers from './schema/with-pointers.json';
export default {
components: { FormSchema },
data: () => ({
schema: {}
}),
created () {
$RefParser.dereference(schemaWithPointers)
.then((schema) => {
// `schema` is the resolved schema that contains your entire JSON
// Schema, including referenced files, combined into a single object
this.schema = schema;
});
}
}
见 json-schema-ref-parser 文档页面 更多细节.
与 allOf 关键词
装入 JSON Schema 包含 allOf 关键字,需要安装
额外扶养 json - schema - 综合起来
帮助FormSchema正常工作:
import mergeAllOf from 'json-schema-merge-allof';
import FormSchema from '@formschema/native';
import schemaWithAllof from './schema/with-allof.json';
export default {
components: { FormSchema },
data: () => ({
schema: mergeAllOf(schemaWithAllof)
})
}
见 json-sema-commerce- all of 文档页面 更多细节.
数据验证
原生 HTML5 验证
默认情况下, FormSchema 通过应用验证使用基本的 HTML5 验证 属性。 这已经足够简单的计划了 但你需要 如果您想要验证复杂的方案, 请指定 JSON Schema 验证器 .
自定义验证 API
对于自定义验证,您需要提供 验证函数道具。 。 。 .
Bellow 自定义验证 API :
type MessageInfo = 0;
type MessageSuccess = 1;
type MessageWarining = 2;
type MessageError = 3;
type MessageType = MessageInfo | MessageSuccess | MessageWarining | MessageError;
interface Message {
type?: MessageType;
text: string;
}
interface GenericField<TModel = any> {
readonly id: string;
readonly key: string;
readonly name: string;
readonly isRoot: boolean;
readonly schema: JsonSchema;
readonly required: boolean;
readonly hasChildren: boolean;
readonly initialValue: TModel;
readonly value: TModel;
readonly messages: Required<Message>[];
clear(): void; // clear field
reset(): void; // reset initial field value
addMessage(message: string, type: MessageType = MessageError): void;
clearMessages(recursive: boolean = false): void;
}
自定义 AJV 验证
贝洛是受欢迎的榜样 阿联酋 验证符 :
<template>
<FormSchema v-model="model" v-bind="{ schema, validator }" @submit.prevent="onSubmit">
<button type="submit">Submit</button>
</FormSchema>
</template>
<script>
import Ajv from 'ajv';
import FormSchema from '@formschema/native';
export default {
data: () => ({
schema: {
type: 'object',
properties: {
username: {
type: 'string',
minLength: 5
},
password: {
type: 'string',
minLength: 6
}
},
required: ['username', 'password']
},
model: {},
ajv: new Ajv({ allErrors: true })
}),
computed: {
validate() {
return this.ajv.compile(this.schema);
}
},
methods: {
onSubmit({ field }) {
if (field && this.validator(field)) {
// validation success, submit code here
}
},
validator(field) {
// Clear all messages
field.clearMessages(true);
if (!this.validate(field.value)) {
this.validate.errors.forEach(({ dataPath, message }) => {
const errorField = field.hasChildren
? field.getField(dataPath) || field
: field;
/**
* Add a message to `errorField`.
* The first argument is the message string
* and the second one the message type:
* 0 - Message Info
* 1 - Message Success
* 2 - Message Warning
* 3 - Message Error
*/
errorField.addMessage(message, 3);
});
// Return `false` to cancel the `input` event
return Promise.resolve(false);
}
// Return `true` to trigger the `input` event
return Promise.resolve(true);
}
},
components: { FormSchema }
};
</script>
禁用本地 HTML5 验证
由于FormSchema使用本地 HTML 窗体元素, 属性 novalidate 财务报告和审定财务报表
formvalidate 可用于按
W3C 规格数字 :
如果存在,它们表示表格在下列情况下不予验证: 提交.
这个 无效状态 如果元素是 提交按钮 和元素的formnovalidate属性是存在的,或者如果元素是 窗体所有者是因为novalidate属性存在,以及false否则.
示例: 使用 novalidate
<template>
<FormSchema v-model="model" :schema="schema" novalidate>
<button type="submit">Submit</button>
</FormSchema>
</template>
使用大小写: 执行保存、 取消和提交
禁用窗体验证限制在执行时可能有用 保存 窗体的特性 :
- 用户应该能够保存进度,尽管他们还没有完全输入表格中的数据
- 用户应当能够取消已保存的窗体数据
- 用户应能够提交经验证的表格数据
<template>
<FormSchema v-model="model" :schema="schema" action="/api/blog/post" method="post">
<input type="submit" name="submit" value="Submit">
<input type="submit" formnovalidate name="save" value="Save">
<input type="submit" formnovalidate name="cancel" value="Cancel">
</FormSchema>
</template>
标签翻译
翻译标签而不更改 JSON Schema 文件的简单方法是 使用描述符.
举个例子 第一十八号数字 :
<template>
<FormSchema v-model="model" :schema="schema" :descriptor="descriptor"/>
</template>
<script>
import FormSchema from '@formschema/native';
export default {
data: () => ({
schema: {
type: 'object',
properties: {
firstname: {
type: 'string'
},
lastname: {
type: 'string'
}
}
},
model: {}
}),
computed: {
descriptor() {
properties: {
firstname: {
label: this.$t('firstname.label'),
helper: this.$t('firstname.helper')
},
lastname: {
label: this.$t('lastname.label'),
helper: this.$t('lastname.helper')
}
}
}
},
// `i18n` option, setup locale info for component
// see https://kazupon.github.io/vue-i18n/guide/component.html
i18n: {
messages: {
en: {
firstname: {
label: 'First Name',
helper: 'Your First Name'
},
lastname: {
label: 'Last Name',
helper: 'Your Last Name'
}
},
fr: {
firstname: {
label: 'Prénom',
helper: 'Votre prénom'
},
lastname: {
label: 'Nom',
helper: 'Votre nom'
}
}
}
},
components: { FormSchema }
};
</script>
渲染窗体元素
文本区域
添加一个 text/* 媒体键入字符串计划以制取文本区域元素.
实例 schema.json
{
"type": "string",
"contentMediaType": "text/plain"
}
您也可以使用描述符来强制 Render 使用文本区域 元素 :
示例描述符.json
{
"kind": "textarea"
}
文件输入
使用媒体类型的字符串计划,而不是从头开始 text/* 作为输入文件元素自动渲染.
实例 schema.json
{
"type": "string",
"contentMediaType": "image/png"
}
有一个列表 IANA正式登记的MIME类型, (中文(简体) ), 但所支持的一组类型将是应用程序和操作系统 依赖。 Mozilla开发者网络也维护一个 对网络重要的 MIME 类型列表。 。 。 .
隐藏输入
带有描述符的图案 hidden 作为隐藏输入元素.
实例 schema.json
{
"type": "string"
}
示例描述符.json
{
"kind": "hidden"
}
密码输入
带有描述器的字符串计划 password 用于提供输入
密码元素.
实例 schema.json
{
"type": "string"
}
示例描述符.json
{
"kind": "password"
}
多个复选框
要定义多个复选框,请使用 JSON Schema 关键词 enum
财务报告和审定财务报表 唯一项目数字 :
实例 schema.json
{
"type": "array",
"uniqueItems": true,
"enum": {
"type": "string",
"enum": [
"daily",
"promotion"
]
}
}
示例描述符.json
{
"items": {
"daily": {
"label": "Receive daily updates"
},
"promotion": {
"label": "Receive promotion emails"
}
}
}
分组电台
组合无线电元件,请使用 JSON Schema 关键词 enum
带有 enum 描述符 :
实例 schema.json
{
"type": "string",
"enum": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday",
"saturday",
"sunday"
]
}
示例描述符.json
{
"kind": "enum",
"items": {
"monday": { "label": "Monday" },
"tuesday": { "label": "Tuesday" },
"wednesday": { "label": "Wednesday" },
"thursday": { "label": "Thursday" },
"friday": { "label": "Friday" },
"saturday": { "label": "Saturday" },
"sunday": { "label": "Sunday" }
}
}
选择输入
组合 HTML 选择元素,使用 JSON Schema 关键词 enum
带有 list 描述符 :
实例 schema.json
{
"type": "string",
"enum": [
"monday",
"tuesday",
"wednesday",
"thruday",
"friday",
"saturday",
"sunday"
]
}
示例描述符.json
{
"kind": "list",
"items": {
"monday": { "label": "Monday" },
"tuesday": { "label": "Tuesday" },
"wednesday": { "label": "Wednesday" },
"thursday": { "label": "Thursday" },
"friday": { "label": "Friday" },
"saturday": { "label": "Saturday" },
"sunday": { "label": "Sunday" }
}
}
矩阵输入
制作 阵列字段,定义您的计划,如:
实例 schema.json
{
"type": "array",
"items": {
"type": "string"
}
}
FormSchema 将添加一个按钮以添加更多输入,从而提供文本输入.
Regex 输入
制作 正则输入, (中文(简体) ), 定义您的计划如下:
实例 schema.json
{
"type": "string",
"pattern": "[a-e]+"
}
字段集元素
表单Schema 使用 a <fieldset> 元素到对象 JSON Schema 的组输入:
实例 schema.json
{
"type": "object",
"properties": {
"firstname": {
"type": "string"
},
"lastname": {
"type": "string"
}
},
"required": ["firstname"]
}
使用描述符设置标签和助手 。 也可以改变顺序 用于渲染的属性 :
示例描述符.json
{
"properties": {
"firstname": {
"label": "First Name",
"helper": "Your first name"
},
"lastname": {
"label": "Last Name",
"helper": "Your last name"
}
},
"order": ["lastname", "firstname"]
}
自定义窗体元素
要点 API
type SchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';
type ScalarKind = 'string' | 'password' | 'number' | 'integer' | 'null' | 'boolean' | 'hidden' | 'textarea' | 'image' | 'file' | 'radio' | 'checkbox';
type ItemKind = 'enum' | 'list';
type FieldKind = SchemaType | ScalarKind | ItemKind;
type ComponentsType = 'form' | 'message' | 'button' | 'helper' | FieldKind;
type Component = string | VueComponent | VueAsyncComponent;
interface IComponents {
set(kind: ComponentsType, component: Component): void;
get(kind: ComponentsType, fallbackComponent?: Component): Component;
}
自定义元素示例
要定义自定义元素, 您需要使用 NativeComponents 类和
components 道具 :
// MyCustomComponents.js
// First, import the base class Components from `@formschema/native` package
import { NativeComponents } from '@formschema/native';
// Then declare your custom components as functional components
import { InputElement } from '@/components/InputElement';
import { StateElement } from '@/components/StateElement';
import { ArrayElement } from '@/components/ArrayElement';
import { FieldsetElement } from '@/components/FieldsetElement';
import { ListElement } from '@/components/ListElement';
import { TextareaElement } from '@/components/TextareaElement';
import { MessageElement } from '@/components/Message';
// Finaly, extend the NativeComponents class and define override it
export class MyCustomComponents extends NativeComponents {
constructor() {
super();
this.set('array', ArrayElement);
this.set('boolean', StateElement);
this.set('string', InputElement);
this.set('password', InputElement);
this.set('file', InputElement);
this.set('image', InputElement);
this.set('radio', StateElement);
this.set('checkbox', StateElement);
this.set('enum', FieldsetElement);
this.set('number', InputElement);
this.set('integer', InputElement);
this.set('object', FieldsetElement);
this.set('list', ListElement);
this.set('textarea', TextareaElement);
this.set('message', MessageElement);
}
}
见文件 原生组件.ts 举个例子.
<template>
<FormSchema v-model="model" :schema="schema" :components="components"/>
</template>
<script>
import FormSchema from '@formschema/native'
import { MyCustomComponents } from './MyCustomComponents'
export default {
data: () => ({
schema: { /* ... */ },
components: new MyCustomComponents(),
model: {}
}),
components: { FormSchema }
}
</script>
Vue 元件示例
- 资料来源: 元素/虚拟元件.js
<template>
<FormSchema v-model="model" :schema="schema" :components="components"/>
</template>
<script>
import FormSchema, { NativeComponents } from '@formschema/native'
import createComponents from '@formschema/native/elements/VueMaterial'
export default {
data: () => ({
schema: { /* ... */ },
components: createComponents(NativeComponents),
model: {}
}),
components: { FormSchema }
}
</script>
描述界面
type SchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';
type ParserKind = SchemaType | 'enum' | 'list' | 'textarea' | 'image' | 'file' | 'password';
type ScalarKind = 'string' | 'password' | 'number' | 'integer' | 'null' | 'boolean' | 'hidden' | 'textarea' | 'image' | 'file' | 'radio' | 'checkbox';
type ItemKind = 'enum' | 'list';
type FieldKind = SchemaType | ScalarKind | ItemKind;
type ComponentsType = 'form' | 'message' | 'button' | 'helper' | FieldKind;
type Component = string | VueComponent | AsyncVueComponent;
type SetDescriptor = EnumDescriptor | ArrayDescriptor | ObjectDescriptor;
type Descriptor = ScalarDescriptor | SetDescriptor | ListDescriptor;
type DescriptorConstructor = (field: Field) => Descriptor;
type DescriptorInstance = Descriptor | DescriptorConstructor;
interface DescriptorDefinition<TKind extends FieldKind = FieldKind> {
kind?: TKind;
label?: string;
helper?: string;
visible?: boolean; // by default true. If false, component will be ignored on rendering
component?: Component;
attrs?: {
[attr: string]: unknown;
};
props?: {
[prop: string]: unknown;
};
}
/**
* Describe scalar types like: string, password, number, integer,
* boolean, null, hidden field, textarea element, image and file
* inputs, radio and checkbox elements
*/
interface ScalarDescriptor extends DescriptorDefinition<ScalarKind> {
}
/**
* Use to describe grouped object properties
*/
interface ObjectGroupDescriptor extends DescriptorDefinition {
properties: string[];
}
/**
* Describe JSON Schema with type `object`
*/
interface ObjectDescriptor extends DescriptorDefinition {
layout?: Component; // default: 'fieldset'
properties?: {
[schemaProperty: string]: DescriptorInstance;
};
order?: string[];
groups?: {
[groupId: string]: ObjectGroupDescriptor;
};
}
/**
* Describe JSON Schema with key `enum`
*/
interface ItemsDescriptor<TKind extends ItemKind> extends DescriptorDefinition<TKind> {
items?: {
[itemValue: string]: ScalarDescriptor;
};
}
/**
* Describe HTML Radio Elements
*/
interface EnumDescriptor extends ItemsDescriptor<'enum'> {
layout?: Component; // default: 'fieldset'
}
/**
* Describe HTML Select Element
*/
interface ListDescriptor extends ItemsDescriptor<'list'> {
}
/**
* Describe buttons for array schema
*/
interface ButtonDescriptor<T extends string, A extends Function> extends Partial<ActionButton<A>> {
type: T;
label: string;
tooltip?: string;
visible?: boolean;
component?: Component;
}
type ActionPushTrigger = () => void;
type PushButtonDescriptor = ButtonDescriptor<'push', ActionPushTrigger>;
type MoveUpButtonDescriptor = ButtonDescriptor<'moveUp', ActionPushTrigger>;
type MoveDownButtonDescriptor = ButtonDescriptor<'moveDown', ActionPushTrigger>;
type DeleteButtonDescriptor = ButtonDescriptor<'delete', ActionPushTrigger>;
type UnknownButtonDescriptor = ButtonDescriptor<string, ActionPushTrigger>;
type ArrayItemButton = MoveUpButtonDescriptor
| MoveDownButtonDescriptor
| DeleteButtonDescriptor
| UnknownButtonDescriptor;
/**
* Describe JSON Schema with type `array`
*/
interface ArrayDescriptor extends DescriptorDefinition {
layout?: Component; // default: 'fieldset'
items?: DescriptorInstance[] | DescriptorInstance;
pushButton: PushButtonDescriptor | null;
buttons: ArrayItemButton[];
}
使用大小写
分组字段
FormSchema可以通过组合来帮助您组织您的形式字段. 请检查 对象描述器定义。 。 。 .
实例 schema.json
{
"type": "object",
"properties": {
"lastname": {
"type": "string"
},
"firstname": {
"type": "string"
},
"city": {
"type": "string"
}
}
}
示例描述符.json
{
"groups": {
"name": {
"label": "Your name",
"properties": ["firstname", "lastname"]
},
"location": {
"label": "Your location",
"properties": ["city"]
}
}
}
不分组的结果
<form id="id-form">
<fieldset id="id-form-field">
<div data-fs-kind="string" data-fs-type="text" data-fs-field="lastname"><label for="id-form-field-lastname"></label>
<div data-fs-input="text"><input id="id-form-field-lastname" type="text" name="lastname"></div>
</div>
<div data-fs-kind="string" data-fs-type="text" data-fs-field="firstname"><label for="id-form-field-firstname"></label>
<div data-fs-input="text"><input id="id-form-field-firstname" type="text" name="firstname"></div>
</div>
<div data-fs-kind="string" data-fs-type="text" data-fs-field="city"><label for="id-form-field-city"></label>
<div data-fs-input="text"><input id="id-form-field-city" type="text" name="city"></div>
</div>
</fieldset>
</form>
组合的结果
<form id="id-form">
<fieldset id="id-form-field">
<div data-fs-group="name">
<div data-fs-group-label="name">Your name</div>
<div data-fs-group-nodes="2">
<div data-fs-kind="string" data-fs-type="text" data-fs-field="firstname"><label for="id-form-field-firstname"></label>
<div data-fs-input="text"><input id="id-form-field-firstname" type="text" name="firstname"></div>
</div>
<div data-fs-kind="string" data-fs-type="text" data-fs-field="lastname"><label for="id-form-field-lastname"></label>
<div data-fs-input="text"><input id="id-form-field-lastname" type="text" name="lastname"></div>
</div>
</div>
</div>
<div data-fs-group="location">
<div data-fs-group-label="location">Your location</div>
<div data-fs-group-nodes="1">
<div data-fs-kind="string" data-fs-type="text" data-fs-field="city"><label for="id-form-field-city"></label>
<div data-fs-input="text"><input id="id-form-field-city" type="text" name="city"></div>
</div>
</div>
</div>
</fieldset>
</form>
捐款
请看 贡献指南。 。 。 .
许可证
根据麻省理工学院的许可。 见 自由主义 以备详细文件.