datatypes w = "http://whattf.org/datatype-draft"

# #####################################################################
##  RELAX NG Schema for HTML 5: Web Forms 2.0 markup                  #
# #####################################################################

## Shared attributes for form controls

	common-form.attrs &=
		( common-form.attrs.form? )

	common-form.attrs.form |= 
		attribute form {
			common.data.idref
		}

	shared-form.attrs.formaction =
		attribute formaction {
			common.data.uri.non-empty
		}

	shared-form.attrs.formenctype =
		attribute formenctype {
			shared-form.attrs.formenctype.data
		}
		shared-form.attrs.formenctype.data = 
			(	w:string "application/x-www-form-urlencoded" 
			|	w:string "multipart/form-data"
			|	w:string "text/plain"
			)

	shared-form.attrs.formmethod =
		attribute formmethod {
			shared-form.attrs.formmethod.data
		}
		shared-form.attrs.formmethod.data = 
			( w:string "get"
			| w:string "post"
			| w:string "dialog"
			)

	shared-form.attrs.formtarget = 
		attribute formtarget {
			common.data.browsing-context-or-keyword
		}

	shared-form.attrs.formnovalidate = 
		attribute formnovalidate {
			w:string "formnovalidate" | w:string ""
		}

	shared-form.attrs.pattern = 
		attribute pattern {
			form.data.pattern
		}

	shared-form.attrs.template = 
		attribute template {
			common.data.idref
		}

	shared-form.attrs.required = 
		attribute required {
			w:string "required" | w:string ""
		}

	shared-form.attrs.placeholder = 
		attribute placeholder {
			form.data.stringwithoutlinebreaks
		}

	shared-form.attrs.dirname = 
		attribute dirname {
			form.data.nonemptystring
		}

	shared-form.attrs.minlength =
		attribute minlength {
			common.data.integer.non-negative
		}

## Shared attributes for <input>
		
	shared-input-no-size.attrs =
		(	input.attrs.autocomplete?
		&	input.attrs.list?
		&	shared-form.attrs.maxlength?
		&	shared-form.attrs.minlength?
		&	shared-form.attrs.pattern?
		&	shared-form.attrs.placeholder?
		&	shared-form.attrs.readonly?
		&	shared-form.attrs.required?
		)

	shared-input-no-list.attrs =
		(	input.attrs.autocomplete?
		&	shared-form.attrs.maxlength?
		&	shared-form.attrs.minlength?
		&	shared-form.attrs.pattern?
		&	shared-form.attrs.placeholder?
		&	shared-form.attrs.readonly?
		&	shared-form.attrs.required?
		&	shared-form.attrs.size?
		)

	shared-input.attrs =
		(	shared-input-no-size.attrs
		&	shared-form.attrs.size?
		)

	input.attrs.list = 
		attribute list {
			common.data.idref
		}
	
	input.attrs.step.float = 
		attribute step {
			w:string "any" | common.data.float.positive
		}
	
	input.attrs.step.integer = 
		attribute step {
			w:string "any" | common.data.integer.positive 
		}
	
	input.attrs.multiple = 
		attribute multiple {
			w:string "multiple" | w:string ""
		}

## autocomplete

	input.attrs.autocomplete.any =
		attribute autocomplete {
			(	w:string "on" | w:string "off"
			|	common.data.autocomplete.any
			)
		}

	input.attrs.autocomplete =
		attribute autocomplete {
			string
		}

## Hidden String: <input type='hidden'>, Extensions

	input.hidden.attrs &=
		(	input.attrs.autocomplete?
		&	shared-form.attrs.dirname?
		)

## Text Field: <input type='text'>, Extensions

	input.text.attrs &=
		(	input.attrs.autocomplete?
		&	shared-form.attrs.dirname?
		&	input.attrs.list?
		&	shared-form.attrs.pattern?
		&	shared-form.attrs.required?
		&	shared-form.attrs.placeholder?
		&	shared-form.attrs.minlength?
		)

## Password Field: <input type='password'>, Extensions

	input.password.attrs &=
		(	input.attrs.autocomplete?
		&	shared-form.attrs.dirname?
		&	input.attrs.list?
		&	shared-form.attrs.pattern?
		&	shared-form.attrs.placeholder?
		&	aria.prop.placeholder?  # specified here because type=password has no implicit role
		&	shared-form.attrs.required?
		&	aria.prop.required?  # specified here because type=password has no implicit role
		&	shared-form.attrs.minlength?
		)

## Checkbox <input type='checkbox'>, Extensions

	input.checkbox.attrs &=
		(	shared-input.attrs
		)

## Radiobutton: <input type='radio'>, Extensions

	input.radio.attrs &=
		(	shared-input.attrs
		)

## Scripting Hook Button: <input type='button'>, Extensions

	input.button.attrs &=
		(	shared-input.attrs	)

## Submit Button: <input type='submit'>, Extensions

	input.submit.attrs &=
		(	shared-input.attrs
		&	shared-form.attrs.dirname?
		&	shared-form.attrs.formaction?
		&	shared-form.attrs.formenctype?
		&	shared-form.attrs.formmethod?
		&	shared-form.attrs.formtarget?
		&	shared-form.attrs.formnovalidate?
		)

## Reset Button: <input type='reset'>, Extensions

	input.reset.attrs &=
		(	shared-input.attrs	)

## File Upload: <input type='file'>, Extensions

	input.file.attrs &=
		(	shared-input.attrs
		&	input.attrs.multiple?
		&	aria.prop.required?
		&	input.input.attrs.capture?
		)
		input.input.attrs.capture =
			attribute capture {
				w:string "user" | w:string "environment"
			}

## Image Submit Button: <input type='image'>, Extensions

	input.image.attrs &=
		(	shared-input.attrs
		&	shared-form.attrs.formaction?
		&	shared-form.attrs.formenctype?
		&	shared-form.attrs.formmethod?
		&	shared-form.attrs.formtarget?
		&	shared-form.attrs.formnovalidate?
		&	input.image.attrs.height?
		&	input.image.attrs.width?
		)	
		input.image.attrs.height =
			attribute height {
				common.data.integer.non-negative
			}
		input.image.attrs.width =
			attribute width {
				common.data.integer.non-negative
			}

## Date and Time with No Time Zone Information: <input type='datetime-local'>

	input.datetime-local.elem = 
		element input { input.datetime-local.attrs }
	input.datetime-local.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input.attrs
		&	input.datetime-local.attrs.type
		&	input.datetime-local.attrs.min?
		&	aria.prop.valuemin?
		&	input.datetime-local.attrs.max?
		&	aria.prop.valuemax?
		&	input.attrs.step.float?
		&	aria.prop.required?
		&	input.datetime-local.attrs.value?
		)	
		input.datetime-local.attrs.type = 
			attribute type {
				w:string "datetime-local"
			}
		input.datetime-local.attrs.min =
			attribute min {
				form.data.datetime-local
			}
		input.datetime-local.attrs.max =
			attribute max {
				form.data.datetime-local			
			}	
		input.datetime-local.attrs.value =
			attribute value {
				w:string "" | form.data.datetime-local
			}
		
	input.elem |= input.datetime-local.elem

## Date: <input type='date'>

	input.date.elem = 
		element input { input.date.attrs }
	input.date.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input.attrs
		&	input.date.attrs.type
		&	input.date.attrs.min?
		&	aria.prop.valuemin?
		&	input.date.attrs.max?
		&	aria.prop.valuemax?
		&	aria.prop.required?
		&	input.attrs.step.integer?
		&	input.date.attrs.value?
		)	
		input.date.attrs.type = 
			attribute type {
				w:string "date"
			}
		input.date.attrs.min =
			attribute min {
				form.data.date
			}
		input.date.attrs.max =
			attribute max {
				form.data.date			
			}	
		input.date.attrs.value =
			attribute value {
				w:string "" | form.data.date
			}
		
	input.elem |= input.date.elem

## Year and Month: <input type='month'>

	input.month.elem = 
		element input { input.month.attrs }
	input.month.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input.attrs
		&	input.month.attrs.type
		&	input.month.attrs.min?
		&	aria.prop.valuemin?
		&	input.month.attrs.max?
		&	aria.prop.valuemax?
		&	aria.prop.required?
		&	input.attrs.step.integer?
		&	input.month.attrs.value?
		)	
		input.month.attrs.type = 
			attribute type {
				w:string "month"
			}
		input.month.attrs.min =
			attribute min {
				form.data.month
			}
		input.month.attrs.max =
			attribute max {
				form.data.month			
			}	
		input.month.attrs.value =
			attribute value {
				w:string "" | form.data.month
			}
		
	input.elem |= input.month.elem

## Time without Time Zone Information: <input type='time'>

	input.time.elem = 
		element input { input.time.attrs }
	input.time.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input.attrs
		&	input.time.attrs.type
		&	input.time.attrs.min?
		&	aria.prop.valuemin?
		&	input.time.attrs.max?
		&	aria.prop.valuemax?
		&	aria.prop.required?
		&	input.attrs.step.float?
		&	input.time.attrs.value?
		)	
		input.time.attrs.type = 
			attribute type {
				w:string "time"
			}
		input.time.attrs.min =
			attribute min {
				form.data.time
			}
		input.time.attrs.max =
			attribute max {
				form.data.time			
			}	
		input.time.attrs.value =
			attribute value {
				w:string "" | form.data.time
			}
		
	input.elem |= input.time.elem

## Year and Week: <input type='week'>

	input.week.elem = 
		element input { input.week.attrs }
	input.week.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input.attrs
		&	input.week.attrs.type
		&	input.week.attrs.min?
		&	aria.prop.valuemin?
		&	input.week.attrs.max?
		&	aria.prop.valuemax?
		&	aria.prop.required?
		&	input.attrs.step.integer?
		&	input.week.attrs.value?
		)	
		input.week.attrs.type = 
			attribute type {
				w:string "week"
			}
		input.week.attrs.min =
			attribute min {
				form.data.week
			}
		input.week.attrs.max =
			attribute max {
				form.data.week			
			}	
		input.week.attrs.value =
			attribute value {
				w:string "" | form.data.week
			}
		
	input.elem |= input.week.elem

## Number: <input type='number'>

	input.number.elem = 
		element input { input.number.attrs }
	input.number.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input-no-size.attrs
		&	input.number.attrs.type
		&	input.number.attrs.min?
		&	input.number.attrs.max?
		&	input.attrs.step.float?
		&	input.number.attrs.value?
		&	(	common.attrs.aria.implicit.spinbutton
			|	common.attrs.aria.role.spinbutton
			)?
		)	
		input.number.attrs.type = 
			attribute type {
				w:string "number"
			}
		input.number.attrs.min =
			attribute min {
				common.data.float
			}
		input.number.attrs.max =
			attribute max {
				common.data.float			
			}	
		input.number.attrs.value =
			attribute value {
				w:string "" | common.data.float
			}
		
	input.elem |= input.number.elem

## Imprecise Number: <input type='range'>

	input.range.elem = 
		element input { input.range.attrs }
	input.range.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input-no-size.attrs
		&	input.range.attrs.type
		&	input.range.attrs.min?
		&	input.range.attrs.max?
		&	input.attrs.step.float?
		&	input.range.attrs.value?
		&	(	common.attrs.aria.implicit.slider
			|	common.attrs.aria.role.slider
			)?
		)	
		input.range.attrs.type = 
			attribute type {
				w:string "range"
			}
		input.range.attrs.min =
			attribute min {
				common.data.float
			}
		input.range.attrs.max =
			attribute max {
				common.data.float			
			}	
		input.range.attrs.value =
			attribute value {
				common.data.float
			}
		
	input.elem |= input.range.elem

## Email Address: <input type='email'>

	input.email.elem = 
		element input { input.email.attrs }	
	input.email.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input-no-list.attrs
		&	shared-form.attrs.dirname?
		&	input.email.attrs.type
		&	(	(	input.attrs.multiple
				&	input.email.attrs.value.multiple?
				)
			|	input.email.attrs.value.single?
			)?
		&	(
				(	common.attrs.aria.implicit.textbox
				|	common.attrs.aria.role.textbox
				)?
			|	(	input.attrs.list
				&	(	common.attrs.aria.implicit.combobox
					|	common.attrs.aria.role.combobox
					)?
				)?
			)
		)	
		input.email.attrs.type = 
			attribute type {
				w:string "email"
			}
		input.email.attrs.value.single =
			attribute value {
				form.data.emailaddress
			}
		input.email.attrs.value.multiple =
			attribute value {
				form.data.emailaddresslist
			}
		
	input.elem |= input.email.elem

## IRI: <input type='url'>

	input.url.elem = 
		element input { input.url.attrs }
	input.url.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input-no-list.attrs
		&	shared-form.attrs.dirname?
		&	input.url.attrs.type
		&	input.url.attrs.value?
		&	(
				(	common.attrs.aria.implicit.textbox
				|	common.attrs.aria.role.textbox
				)?
			|	(	input.attrs.list
				&	(	common.attrs.aria.implicit.combobox
					|	common.attrs.aria.role.combobox
					)?
				)?
			)
		)
		input.url.attrs.type = 
			attribute type {
				w:string "url"
			}
		input.url.attrs.value =
			attribute value {
				w:string "" | common.data.uri.absolute
			}
		
	input.elem |= input.url.elem

## Search: <input type='search'>

	input.search.elem = 
		element input { input.search.attrs }
	input.search.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input.attrs
		&	input.search.attrs.type
		&	input.search.attrs.value?
		&	shared-form.attrs.dirname?
		&	(	common.attrs.aria.implicit.searchbox
			|	common.attrs.aria.role.searchbox
			)?
		)	
		input.search.attrs.type = 
			attribute type {
				w:string "search"
			}
		input.search.attrs.value =
			attribute value {
				form.data.stringwithoutlinebreaks
			}
		
	input.elem |= input.search.elem

## Telephone Number: <input type='tel'>

	input.tel.elem = 
		element input { input.tel.attrs }	
	input.tel.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	shared-input-no-list.attrs
		&	shared-form.attrs.dirname?
		&	input.tel.attrs.type
		&	input.tel.attrs.value?
		&	(
				(	common.attrs.aria.implicit.textbox
				|	common.attrs.aria.role.textbox
				)?
			|	(	input.attrs.list
				&	(	common.attrs.aria.implicit.combobox
					|	common.attrs.aria.role.combobox
					)?
				)?
			)
		)
		input.tel.attrs.type = 
			attribute type {
				w:string "tel"
			}
		input.tel.attrs.value =
			attribute value {
				form.data.stringwithoutlinebreaks
			}
		
	input.elem |= input.tel.elem

## Color: <input type='color'>

	input.color.elem = 
		element input { input.color.attrs }	
	input.color.attrs = 
		(	common.attrs
		&	common-form.attrs
		&	input.color.attrs.type
		&	input.color.attrs.value?
		&	input.color.attrs.alpha?
		&	input.color.attrs.colorspace?
		&	shared-input.attrs
		)	
		input.color.attrs.type = 
			attribute type {
				w:string "color"
			}
		input.color.attrs.value =
			attribute value {
				w:string "" | form.data.color
			}
		input.color.attrs.alpha =
			attribute alpha {
				w:string "alpha" | w:string ""
			}
		input.color.attrs.colorspace =
			attribute colorspace {
				w:string "limited-srgb" | w:string "display-p3"
			}
		
	input.elem |= input.color.elem

## Form Output: <output>

	output.elem =
		element output { output.inner & output.attrs }
	output.attrs =
		(	common.attrs
		&	common-form.attrs.name?
		&	common-form.attrs.form?
		&	output.attrs.for?
		&	(	common.attrs.aria.implicit.status
			|	common.attrs.aria
			)?
		)
		output.attrs.for = 
			attribute for {
				common.data.idrefs #REVISIT spec says space--not whitespace
			}
	output.inner =
		( common.inner.phrasing )

	common.elem.phrasing |= output.elem

## Text Area: <textarea>, extensions

	textarea.attrs.rows-and-cols-wf1.inner &=
		notAllowed
	textarea.attrs.rows-and-cols-wf1 |= 
		empty
	textarea.attrs &=
		(	shared-form.attrs.maxlength?
		&	shared-form.attrs.minlength?
		&	shared-form.attrs.required? 
		&	textarea.attrs.placeholder?
		&	shared-form.attrs.dirname?
		&	textarea.attrs.rows?
		&	(	(	textarea.attrs.wrap.hard 
				&	textarea.attrs.cols
				)
			|	(	textarea.attrs.wrap.soft?
				&	textarea.attrs.cols?
				)
			)
		&	input.attrs.autocomplete.any?
		)
		textarea.attrs.wrap.hard =
			attribute wrap {
				w:string "hard"
			}
		textarea.attrs.wrap.soft =
			attribute wrap {
				w:string "soft"
			}
		textarea.attrs.placeholder =
			attribute placeholder {
				string
			}

## List of Prefill Data: <datalist>

	#REVISIT should the options in datalist be non-selectable?

	datalist.elem =
		element datalist { datalist.inner & datalist.attrs }
	datalist.inner =
		( option.elem* & common.inner.phrasing )
	datalist.attrs =
		(	common.attrs
		)	

	common.elem.phrasing |= datalist.elem

## Complex Submit Button: <button type='submit'>, extensions

	button.submit.attrs &=
		(	shared-form.attrs.formaction? 
		&	shared-form.attrs.formenctype? 
		&	shared-form.attrs.formmethod? 
		&	shared-form.attrs.formtarget? 
		&	shared-form.attrs.formnovalidate? 
		)
	

## Form: <form>, extensions
	form.attrs &= 
		(	form.attrs.novalidate?
		&	form.attrs.target?
		&	form.attrs.autocomplete?
		)
		form.attrs.novalidate = 
			attribute novalidate {
				w:string "novalidate" | w:string ""
			}
		form.attrs.target = 
			attribute target {
				common.data.browsing-context-or-keyword
			}
		form.attrs.autocomplete = 
			attribute autocomplete {
				w:string "on" | w:string "off"
			}
		# REVISIT should this be case-insensitive in conforming XHTML documents?
		form.attrs.enctype.data |= 
			( w:string "text/plain" )

## Fieldset: <fieldset>, extensions

	fieldset.attrs &=
		( common-form.attrs )

## Selection Menu: <select>, Extensions

	select.attrs &=
		(	shared-form.attrs.required? 
		&	input.attrs.autocomplete.any?
		)
