| datatypes w = "http://whattf.org/datatype-draft" |
| |
| # ##################################################################### |
| ## RELAX NG Schema for HTML 5: Web Forms 1.0 markup # |
| # ##################################################################### |
| |
| ## Shared attributes for form controls |
| |
| common-form.attrs = |
| ( common-form.attrs.name? |
| & common-form.attrs.disabled? |
| ) |
| |
| common-form.attrs.name = |
| attribute name { |
| string #REVISIT should this be restricted somehow? No & and = perhaps? |
| } |
| |
| common-form.attrs.disabled = |
| attribute disabled { |
| w:string "disabled" | w:string "" |
| } |
| |
| shared-form.attrs.readonly = |
| attribute readonly { |
| w:string "readonly" | w:string "" |
| } |
| |
| shared-form.attrs.maxlength = |
| attribute maxlength { |
| common.data.integer.non-negative |
| } |
| |
| shared-form.attrs.size = |
| attribute size { |
| common.data.integer.positive |
| } |
| |
| # REVISIT tabindex goes in common.attrs |
| |
| ## Shared attributes for <input> |
| |
| input.attrs.checked = |
| attribute checked { |
| w:string "checked" | w:string "" |
| } |
| |
| ## Text Field: <input type='text'> |
| |
| input.text.elem = |
| element input { input.text.attrs } |
| input.text.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.text.attrs.type? |
| & shared-form.attrs.maxlength? |
| & shared-form.attrs.readonly? |
| & shared-form.attrs.size? |
| & input.text.attrs.value? |
| & ( common.attrs.aria.implicit.textbox |
| | common.attrs.aria.implicit.combobox |
| | common.attrs.aria.role.textbox |
| | common.attrs.aria.role.combobox |
| )? |
| ) |
| input.text.attrs.type = |
| attribute type { |
| w:string "text" |
| } |
| input.text.attrs.value = |
| attribute value { |
| form.data.stringwithoutlinebreaks |
| } |
| |
| input.elem = input.text.elem |
| |
| ## Password Field: <input type='password'> |
| |
| input.password.elem = |
| element input { input.password.attrs } |
| input.password.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.password.attrs.type |
| & shared-form.attrs.maxlength? |
| & shared-form.attrs.readonly? |
| & shared-form.attrs.size? |
| & input.password.attrs.value? |
| & ( common.attrs.aria.implicit.textbox |
| | common.attrs.aria.role.textbox |
| )? |
| ) |
| input.password.attrs.type = |
| attribute type { |
| w:string "password" |
| } |
| input.password.attrs.value = |
| attribute value { |
| form.data.stringwithoutlinebreaks |
| } |
| |
| input.elem |= input.password.elem |
| |
| ## Checkbox: <input type='checkbox'> |
| |
| input.checkbox.elem = |
| element input { input.checkbox.attrs } |
| input.checkbox.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.checkbox.attrs.type |
| & input.attrs.checked? |
| & input.checkbox.attrs.value? |
| & ( common.attrs.aria.implicit.checkbox |
| | common.attrs.aria.role.checkbox |
| | common.attrs.aria.role.menuitemcheckbox |
| )? |
| ) |
| input.checkbox.attrs.type = |
| attribute type { |
| w:string "checkbox" |
| } |
| input.checkbox.attrs.value = |
| attribute value { |
| string #REVISIT require non-empty value? |
| } |
| |
| input.elem |= input.checkbox.elem |
| |
| ## Radiobutton: <input type='radio'> |
| |
| input.radio.elem = |
| element input { input.radio.attrs } |
| input.radio.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.radio.attrs.type |
| & input.attrs.checked? |
| & input.radio.attrs.value? |
| & ( common.attrs.aria.implicit.radio |
| | common.attrs.aria.role.radio |
| | common.attrs.aria.role.menuitemradio |
| )? |
| ) |
| input.radio.attrs.type = |
| attribute type { |
| w:string "radio" |
| } |
| input.radio.attrs.value = |
| attribute value { |
| string #REVISIT require non-empty value? |
| } |
| |
| input.elem |= input.radio.elem |
| |
| ## Scripting Hook Button: <input type='button'> |
| |
| input.button.elem = |
| element input { input.button.attrs } |
| input.button.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.button.attrs.type |
| & input.button.attrs.value? |
| & ( common.attrs.aria.implicit.button |
| | common.attrs.aria.role.button |
| | common.attrs.aria.role.link |
| | common.attrs.aria.role.menuitem |
| | common.attrs.aria.role.menuitemcheckbox |
| | common.attrs.aria.role.menuitemradio |
| | common.attrs.aria.role.radio |
| )? |
| ) |
| input.button.attrs.type = |
| attribute type { |
| w:string "button" |
| } |
| input.button.attrs.value = |
| attribute value { |
| string #REVISIT require non-empty value? |
| } |
| |
| input.elem |= input.button.elem |
| #REVISIT should this be enabled by a scripting module only? |
| |
| ## Submit Button: <input type='submit'> |
| |
| input.submit.elem = |
| element input { input.submit.attrs } |
| input.submit.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.submit.attrs.type |
| & input.submit.attrs.value? |
| & ( common.attrs.aria.implicit.button |
| | common.attrs.aria.role.button |
| )? |
| ) |
| input.submit.attrs.type = |
| attribute type { |
| w:string "submit" |
| } |
| input.submit.attrs.value = |
| attribute value { |
| string #REVISIT require non-empty value? |
| } |
| |
| input.elem |= input.submit.elem |
| |
| ## Reset Button: <input type='reset'> |
| |
| input.reset.elem = |
| element input { input.reset.attrs } |
| input.reset.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.reset.attrs.type |
| & input.reset.attrs.value? |
| & ( common.attrs.aria.implicit.button |
| | common.attrs.aria.role.button |
| )? |
| ) |
| input.reset.attrs.type = |
| attribute type { |
| w:string "reset" |
| } |
| input.reset.attrs.value = |
| attribute value { |
| string #REVISIT require non-empty value? |
| } |
| |
| input.elem |= input.reset.elem |
| # REVISIT does reset make sense outside a form? |
| |
| ## File Upload: <input type='file'> |
| |
| input.file.elem = |
| element input { input.file.attrs } |
| input.file.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.file.attrs.type |
| & input.file.attrs.accept? |
| & common.attrs.aria? |
| ) |
| input.file.attrs.type = |
| attribute type { |
| w:string "file" |
| } |
| input.file.attrs.accept = |
| attribute accept { |
| form.data.mimetypelist |
| } |
| |
| input.elem |= input.file.elem |
| |
| ## Hidden String: <input type='hidden'> |
| |
| input.hidden.elem = |
| element input { input.hidden.attrs } |
| input.hidden.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.hidden.attrs.type |
| & input.hidden.attrs.value? |
| & common.attrs.aria? |
| ) |
| input.hidden.attrs.type = |
| attribute type { |
| w:string "hidden" |
| } |
| input.hidden.attrs.value = |
| attribute value { |
| string |
| } |
| |
| input.elem |= input.hidden.elem |
| |
| ## Image Submit Button: <input type='image'> |
| |
| input.image.elem = |
| element input { input.image.attrs } |
| input.image.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & input.image.attrs.type |
| & input.image.attrs.alt |
| & input.image.attrs.src? |
| & ( common.attrs.aria.implicit.button |
| | common.attrs.aria.role.button |
| | common.attrs.aria.role.link |
| | common.attrs.aria.role.menuitem |
| | common.attrs.aria.role.menuitemcheckbox |
| | common.attrs.aria.role.menuitemradio |
| | common.attrs.aria.role.radio |
| )? |
| ) |
| input.image.attrs.type = |
| attribute type { |
| w:string "image" |
| } |
| input.image.attrs.alt = |
| attribute alt { |
| form.data.nonemptystring |
| } |
| input.image.attrs.src = |
| attribute src { |
| common.data.uri.non-empty |
| } |
| |
| input.elem |= input.image.elem |
| |
| common.elem.phrasing |= input.elem |
| |
| ## Text Area: <textarea> |
| |
| textarea.elem = |
| element textarea { textarea.inner & textarea.attrs } |
| textarea.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & shared-form.attrs.readonly? |
| & textarea.attrs.rows-and-cols-wf1 |
| & ( common.attrs.aria.implicit.textbox |
| | common.attrs.aria.role.presentation |
| | common.attrs.aria.role.menuitem |
| | common.attrs.aria.role.textbox |
| )? |
| #FIXME onfocus, onblur, onselect,onchange |
| ) |
| # This is ugly. |
| textarea.attrs.rows-and-cols-wf1 = |
| textarea.attrs.rows-and-cols-wf1.inner |
| textarea.attrs.rows-and-cols-wf1.inner = |
| ( textarea.attrs.cols |
| & textarea.attrs.rows |
| ) |
| textarea.attrs.cols = |
| attribute cols { |
| common.data.integer.positive |
| } |
| textarea.attrs.rows = |
| attribute rows { |
| common.data.integer.positive |
| } |
| textarea.inner = |
| ( text ) |
| |
| common.elem.phrasing |= textarea.elem |
| |
| # Due to limitations with interleave, handling single/multiple selection |
| # enforcement in RELAX NG seems to be possible but really awkward. |
| # Tried it. Leaving it to Schematron. |
| |
| ## Select menu option: <option selected> |
| |
| option.elem = |
| element option { option.inner & option.attrs } |
| option.attrs = |
| ( common.attrs |
| & common-form.attrs.disabled? |
| & option.attrs.selected? |
| & option.attrs.label? |
| & option.attrs.value? |
| & ( common.attrs.aria.implicit.option |
| | common.attrs.aria.role.option |
| | common.attrs.aria.role.menuitem |
| | common.attrs.aria.role.menuitemradio |
| | common.attrs.aria.role.menuitemcheckbox |
| | common.attrs.aria.role.presentation |
| )? |
| ) |
| option.attrs.selected = |
| attribute selected { |
| w:string "selected" | w:string "" |
| } |
| option.attrs.label = |
| attribute label { |
| form.data.nonemptystring |
| } |
| option.attrs.value = |
| attribute value { |
| string |
| } |
| option.inner = |
| ( text ) |
| |
| ## Option Group: <optgroup> |
| |
| optgroup.elem = |
| element optgroup { optgroup.inner & optgroup.attrs } |
| optgroup.attrs = |
| ( common.attrs |
| & optgroup.attrs.label |
| & common-form.attrs.disabled? |
| & ( common.attrs.aria.role.presentation |
| | common.attrs.aria.role.menuitem |
| )? |
| ) |
| optgroup.attrs.label = |
| attribute label { |
| string |
| } |
| optgroup.inner = |
| ( option.elem* |
| & common.elem.script-supporting* |
| ) |
| |
| ## Selection Menu: <select> |
| |
| select.elem = |
| element select { select.inner & select.attrs } |
| select.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & select.attrs.size? |
| & select.attrs.multiple? |
| # FIXME onfocus, onblur, onchange |
| & ( common.attrs.aria.implicit.listbox |
| | common.attrs.aria.role.listbox # aria-multiselectable depends on "multiple" value; check in assertions |
| | common.attrs.aria.role.menu |
| | common.attrs.aria.role.presentation |
| | common.attrs.aria.role.menuitem |
| )? |
| ) |
| select.attrs.size = |
| attribute size { |
| common.data.integer.positive |
| } |
| select.attrs.multiple = |
| attribute multiple { |
| w:string "multiple" | w:string "" |
| } |
| select.inner = |
| ( optgroup.elem* |
| & option.elem* |
| & common.elem.script-supporting* |
| ) |
| |
| common.elem.phrasing |= select.elem |
| |
| ## Shared Definitions for Complex Button |
| |
| button.attrs.value = |
| attribute value { |
| string |
| } |
| button.inner = |
| ( common.inner.phrasing ) |
| |
| ## Complex Submit Button: <button type='submit'> |
| |
| button.submit.elem = |
| element button { button.inner & button.submit.attrs } |
| button.submit.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & button.submit.attrs.type? |
| & button.attrs.value? |
| & ( common.attrs.aria.implicit.button |
| | common.attrs.aria.role.button |
| | common.attrs.aria.role.link |
| | common.attrs.aria.role.menuitem |
| | common.attrs.aria.role.menuitemcheckbox |
| | common.attrs.aria.role.menuitemradio |
| | common.attrs.aria.role.radio |
| )? |
| ) |
| button.submit.attrs.type = |
| attribute type { |
| w:string "submit" |
| } |
| |
| button.elem = button.submit.elem |
| |
| ## Complex Reset Button: <button type='reset'> |
| |
| button.reset.elem = |
| element button { button.inner & button.reset.attrs } |
| button.reset.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & button.reset.attrs.type |
| & button.attrs.value? #REVISIT I guess this still affects the DOM |
| & ( common.attrs.aria.implicit.button |
| | common.attrs.aria.role.button |
| | common.attrs.aria.role.link |
| | common.attrs.aria.role.menuitem |
| | common.attrs.aria.role.menuitemcheckbox |
| | common.attrs.aria.role.menuitemradio |
| | common.attrs.aria.role.radio |
| )? |
| ) |
| button.reset.attrs.type = |
| attribute type { |
| w:string "reset" |
| } |
| |
| button.elem |= button.reset.elem |
| |
| ## Complex Push Button: <button type='button'> |
| |
| button.button.elem = |
| element button { button.inner & button.button.attrs } |
| button.button.attrs = |
| ( common.attrs |
| & common-form.attrs |
| & button.button.attrs.type |
| & button.attrs.value? #REVISIT I guess this still affects the DOM |
| & ( common.attrs.aria.implicit.button |
| | common.attrs.aria.role.button |
| | common.attrs.aria.role.link |
| | common.attrs.aria.role.menuitem |
| | common.attrs.aria.role.menuitemcheckbox |
| | common.attrs.aria.role.menuitemradio |
| | common.attrs.aria.role.radio |
| )? |
| ) |
| button.button.attrs.type = |
| attribute type { |
| w:string "button" |
| } |
| |
| button.elem |= button.button.elem |
| |
| common.elem.phrasing |= button.elem |
| |
| ## Form: <form> |
| |
| form.elem = |
| element form { form.inner & form.attrs } |
| form.attrs = |
| ( common.attrs |
| & form.attrs.action? #REVISIT Should this be required anyway? |
| & form.attrs.method? |
| & form.attrs.enctype? |
| & common-form.attrs.name? |
| & form.attrs.accept-charset? |
| & common.attrs.aria? |
| ) |
| form.attrs.action = |
| attribute action { |
| common.data.uri.non-empty |
| } |
| form.attrs.method = |
| attribute method { |
| form.attrs.method.data |
| } |
| form.attrs.method.data = |
| ( w:string "get" | w:string "post" ) |
| form.attrs.enctype = |
| attribute enctype { |
| form.attrs.enctype.data |
| } |
| form.attrs.enctype.data = |
| ( w:string "application/x-www-form-urlencoded" |
| | w:string "multipart/form-data" |
| ) |
| form.attrs.accept-charset = |
| attribute accept-charset { |
| form.data.charsetlist |
| } |
| form.inner = |
| ( common.inner.flow ) |
| |
| common.elem.flow |= form.elem |
| |
| ## Fieldset: <fieldset> |
| |
| fieldset.elem = |
| element fieldset { fieldset.inner & fieldset.attrs } |
| fieldset.attrs = |
| ( common.attrs |
| & ( common.attrs.aria.implicit.group |
| | common.attrs.aria |
| )? |
| ) |
| fieldset.inner = |
| ( legend.elem? #REVISIT should this be required? |
| , common.inner.flow |
| ) |
| |
| common.elem.flow |= fieldset.elem |
| |
| ## Label: <label> |
| |
| label.elem = |
| element label { label.inner & label.attrs } |
| label.attrs = |
| ( common.attrs |
| & label.attrs.for? |
| & ( common.attrs.aria.role.presentation |
| | common.attrs.aria.role.menuitem |
| )? |
| ) |
| label.attrs.for = |
| attribute for { |
| common.data.idref |
| } |
| label.inner = |
| ( common.inner.phrasing ) #REVISIT making obvious guess |
| |
| common.elem.phrasing |= label.elem |
| |