Confirmed users
1,396
edits
(21 intermediate revisions by the same user not shown) | |||
Line 293: | Line 293: | ||
<code> | <code> | ||
AccessibleElement .''actions'' | AccessibleElement .''actions'' | ||
::Returns a [[# | ::Returns a [[#ActionMap|ActionMap]] object of actions exposed by the accessible element. The returned object is not live, i.e. it is not updated if the accessible element actions change. | ||
</code> | </code> | ||
Line 374: | Line 374: | ||
====ActionMap==== | |||
Accessible actions are presented by <code>ActionMap</code> map like object of pairs { action name, action object }. | |||
Accessible actions are presented by <code> | |||
<pre> | <pre> | ||
interface | interface ActionMap { | ||
readonly maplike<DOMString, Action>; | readonly maplike<DOMString, Action>; | ||
}; | }; | ||
Line 477: | Line 474: | ||
}); | }); | ||
</pre> | </pre> | ||
====Questions/concerns==== | |||
* Interactions should be extended to allow to specify a control that triggers the action. The concept is described by InidieUI: you can use mouse, touchscreen, keyboard, voice control or a control element to invoke the action. Maybe Interactions should be renamed to Triggers to share terms with IndieUI. | |||
Here's the image of InideUI action/interaction concept. | |||
<div style="height: 254px; overflow: hidden;"> | |||
http://www.w3.org/WAI/intro/iui-scroll.png | |||
</div> | |||
Alternatively we could introduce relations between actions like "triggers" and "triggeredby". | |||
* What about highlevel actions (uberactions), for example, "press" buttons means "send something somewhere". This may be covered by label. Another example, selected listitem on the left changes a view on the right, "select" actions has meaning of "change view". Or checkbox that enables/disables related controls, "check/uncheck" action means "enable/disable controls". These examples correlates to controlledby/controllerfor relations, but the relations doesn't reveal type of control. | |||
===Parent-child relations=== | ===Parent-child relations=== | ||
Line 561: | Line 573: | ||
AccessiblePos? move(DOMNode container, long offset); | AccessiblePos? move(DOMNode container, long offset); | ||
AccessiblePos? move(DOMPoint); | AccessiblePos? move(DOMPoint); | ||
AccessiblePos? search(Where where, | AccessiblePos? move(Where where, Criteria); | ||
AccessiblePos? search(Where where, Criteria); | |||
readonly attribute AccessibleElement root; | readonly attribute AccessibleElement root; | ||
Line 709: | Line 721: | ||
Construction from a DOM node and offset relative it. See [[#Caret_and_selection|selection]] for examples. | Construction from a DOM node and offset relative it. See [[#Caret_and_selection|selection]] section for examples. | ||
<code> | <code> | ||
Line 772: | Line 784: | ||
Accessible position can be moved through the content by criteria. | Accessible position can be moved through the content by criteria. | ||
AccessiblePos .''move''(Where, Criteria) | AccessiblePos .''move'' (''Where'', ''Criteria'') | ||
::Move the accessible position to the content complying with criteria. | ::Move the accessible position to the content complying with criteria. | ||
::Parameters | ::Parameters | ||
:::''where'' of ''Where'' | :::''where'' of ''Where'' | ||
::::where the search should be performed | ::::where the search should be performed | ||
:::'' | :::''criteria'' of ''Criteria'' | ||
::::function describing a match | ::::function describing a match | ||
:::Return itself if succeeded, otherwise null. | :::Return itself if succeeded, otherwise null. | ||
AccessiblePos .''search''(Where, Criteria) | AccessiblePos .''search'' (''Where'', ''Criteria'') | ||
::Search for content of the given criteria relative the accessible position. | ::Search for content of the given criteria relative the accessible position. | ||
::Parameters | ::Parameters | ||
:::''where'' of ''Where'' | :::''where'' of ''Where'' | ||
::::where the search should be performed | ::::where the search should be performed | ||
:::'' | :::''criteria'' of ''Criteria'' | ||
::::function describing a match | ::::function describing a match | ||
:::Return new instance if succeeded, otherwise null. | :::Return new instance if succeeded, otherwise null. | ||
Line 793: | Line 805: | ||
===== | =====Where to search===== | ||
The search area and the way accessible elements are traversed are defined by <code>Where</code> argument. It defines whether traversal is perfromed by accessible tree hierarchy or by layout on the screen, and whether the traversal is relative of the current position or relative of the root. | |||
<pre> | <pre> | ||
Line 829: | Line 841: | ||
::Search backwards from the accessible position in cycle. | ::Search backwards from the accessible position in cycle. | ||
Where .'' | Where .''first'' | ||
::Search for a first match inside the root. | ::Search for a first match inside the root. | ||
Where .'' | Where .''last'' | ||
::Search backwards (from last to first element) for a first match inside the root. | ::Search backwards (from last to first element) for a first match inside the root. | ||
Line 858: | Line 870: | ||
<b>Example.</b> | |||
<pre> | <pre> | ||
function criteria(el) { } | function criteria(el) { } | ||
var pos1 = new A11ePos(new DOMPoint(x, y), a11edoc).move("forward", criteria); | var pos1 = new A11ePos(new DOMPoint(x, y), a11edoc).move("forward", criteria); | ||
Line 871: | Line 885: | ||
=====Criteria===== | |||
Criteria can be either a literal describing how the position should be moved or a matching function called for every traversed accessible. | |||
<pre> | <pre> | ||
typedef CriteriaLiteral or CriteriaFunc Criteria; | |||
</pre> | </pre> | ||
<pre> | <pre> | ||
enum | enum CriteriaLiteral { | ||
"char", | "char", | ||
"word", | "word", | ||
Line 895: | Line 902: | ||
"paragraph", | "paragraph", | ||
"change", | "change", | ||
"bit | "bit" | ||
}; | }; | ||
</pre> | </pre> | ||
<code> | <code> | ||
CriteriaLiteral .''char'' | |||
::Used to move the position one char long. | ::Used to move the position one char long. | ||
CriteriaLiteral .''word'' | |||
::Used to move the position to the next word. | ::Used to move the position to the next word. | ||
CriteriaLiteral .''sentence'' | |||
::Used to move the position to the next sentence. | ::Used to move the position to the next sentence. | ||
CriteriaLiteral .''line'' | |||
::Used to move the position to beginning of next line or end of previous line. | ::Used to move the position to beginning of next line or end of previous line. | ||
CriteriaLiteral .''paragraph'' | |||
::Used to move the position to beginning of next/previous paragraph. | ::Used to move the position to beginning of next/previous paragraph. | ||
CriteriaLiteral .''change'' | |||
::Used to move the position to next change either of text attribute or new accessible. | ::Used to move the position to next change either of text attribute or new accessible. | ||
CriteriaLiteral .''bit'' | |||
::Used to move the position to next/previous navigable position. For example, from accessible start inside of it to right before accessible outside of it or moving from end of this line to start of next line in case of soft line break lines. | ::Used to move the position to next/previous navigable position. For example, from accessible start inside of it to right before accessible outside of it or moving from end of this line to start of next line in case of soft line break lines. | ||
</code> | </code> | ||
<b>Example #1. Traverse a paragraph by words.</b> | |||
<b>Example. Traverse a paragraph by words.</b> | |||
<pre> | <pre> | ||
var p = document.getElementById("p").a11ement; | var p = document.getElementById("p").a11ement; | ||
var pos1 = new A11ePos(p, " | var pos1 = new A11ePos(p, "begin", p), pos2 = null; | ||
while (pos2 = pos1.search("forward", | while (pos2 = pos1.search("forward", "word")) { | ||
console.log(pos2. | console.log(pos2.text(pos1)); | ||
pos1 = pos2; | pos1 = pos2; | ||
} | } | ||
Line 967: | Line 942: | ||
<pre> | <pre> | ||
<p>Mozilla is a <a href="">free-software</a> community which | <p id="p">Mozilla is a <a href="">free-software</a> community which | ||
produces the <a href="">Firefox web browser</a>.</p> | produces the <a href="">Firefox web browser</a>.</p> | ||
</pre> | </pre> | ||
the log | The script above generates the log "Mozilla ", "is ", "a ", "free-", "software ", "community", "which ", "produces ", "the ", "Firefox ", "web ", "browser." | ||
<pre> | |||
<p id="p">Mo<a href="">zilla</a>.</p> | |||
</pre> | |||
The log is | The log is "Mozilla". | ||
<pre> | <pre> | ||
callback CriteriaFunc = CriteriaLiteral or Offset or "next" (AccessibleElement); | |||
</pre> | </pre> | ||
< | <code> | ||
CriteriaFunc | |||
</ | ::A criteria function used to define an algorithm of the match. | ||
::Returns | |||
:::a criteria term or offset(s) | |||
</code> | |||
If "next" is returned then criteria function is reentered with next traversed accessible. If offset is given then traversing is stopped, the accessible position is moved to the traversed accessible element and given offset. If criteria literal is returned then the accessible position is moved to the position complying the criteria. If it cannot be moved withing current accessible then it reenters with next accessible. | |||
<b> Example. Navigate by widgets and structures, and by words in case of text.</b> | <b> Example. Navigate by widgets and structures, and by words in case of text.</b> | ||
<pre> | <pre> | ||
function | function criteria(aEl) | ||
{ | { | ||
var role = document.taxonOf("role", aEl.role); | var role = document.taxonOf("role", aEl.role); | ||
if (role.is("widget") | if (role.is("widget") | ||
return | return "at"; | ||
if (role.is("structure") | if (role.is("structure") | ||
return "at"; | return "at"; | ||
// Reenters with next accessible if it cannot move to the next | // Reenters with next accessible if it cannot move to the next line within this accessible. | ||
if (role.is("textcontainer")) | if (role.is("textcontainer")) | ||
return " | return "line"; | ||
return "next"; | return "next"; | ||
} | } | ||
pos.move("next", | pos.move("next", criteria); | ||
</pre> | </pre> | ||
====Other methods==== | ====Other methods==== | ||
Line 1,082: | Line 1,057: | ||
<pre> | <pre> | ||
partial interface AccessiblePos { | partial interface AccessiblePos { | ||
DOMString | DOMString text(AccessiblePos pos); | ||
DOMString text(CriteriaLiteral criteria); | |||
readonly attribute AttributeSet textAttributes; | readonly attribute AttributeSet textAttributes; | ||
}; | }; | ||
Line 1,088: | Line 1,064: | ||
<code> | <code> | ||
AccessibleDocument .'' | AccessibleDocument .''text(AccessiblePos)'' | ||
::Returns the text enclosed between this and given accessible positions. | ::Returns the text enclosed between this and given accessible positions. | ||
AccessibleDocument .''text(CriteriaLiteral)'' | |||
::Returns the text at the position complying the given criteria. See [[#Criteria|criteria]] for options. | |||
</code> | </code> | ||
Example how to get first line of the first encountered paragraph: | Example how to get first line of the first encountered paragraph: | ||
<pre> | <pre> | ||
var startPos = new A11ePos().move("first", | function criteria(a) | ||
var endPos = startPos && startPos.search("forward", | { return a.role == "paragraph" ? "being" : "next" }; | ||
var text = startPos. | var startPos = new A11ePos(document).move("first", criteria); | ||
var endPos = startPos && startPos.search("forward", "line"); | |||
var text = startPos.text(startPos, endPos); | |||
</pre> | |||
or same effect by using criteria literal | |||
<pre> | |||
function criteria(a) | |||
{ return a.role == "paragraph" ? "being" : "next" }; | |||
var pos = new A11ePos(document).move("first", criteria); | |||
var text = pos.text("line"); | |||
</pre> | </pre> | ||
Line 1,151: | Line 1,140: | ||
AccessibleDocument .''selectionStart'' | AccessibleDocument .''selectionStart'' | ||
::Get/set selection start. | ::Get/set selection start. | ||
AccessibleDocument .''selectionEnd'' | AccessibleDocument .''selectionEnd'' | ||
Line 1,158: | Line 1,146: | ||
<b>Example</b> | <b>Example.</b> | ||
<pre> | <pre> | ||
Line 1,518: | Line 1,506: | ||
control.relations.add("labelledby", label.a11yment); | control.relations.add("labelledby", label.a11yment); | ||
</pre> | </pre> | ||
Line 1,974: | Line 1,959: | ||
===Implied semantics=== | ===Implied semantics=== | ||
The author | The idea is to help the author to keep the code less verbose as possible. If role implies a number of preset attributes or states then they are present on the accessible element by default, i.e. if the author didn't list them. For example, if <code>listitem</code> role is selectable and focusable by default then the author doesn't have to point <code>selectable</code> and <code>focusable</code> states when he describes a listitem source, in other words, these code snippets are equivalent: | ||
<pre> | <pre> | ||
var | var source1 = { | ||
role: "listitem" | role: "listitem" | ||
}; | }; | ||
var source2 = { | |||
var | |||
role: "listitem", | role: "listitem", | ||
states: [ "selectable" ] | states: [ "selectable", "focusable" ] | ||
}; | }; | ||
</pre> | </pre> | ||
Implied semantics is described by [[#SemanticsProviders|taxonomies]]. | |||
===Conflicts=== | ===Conflicts=== | ||
[to be done conflicts between native semantics, ARIA and this API] | [to be done conflicts between native semantics, ARIA and this API, I tend to think that the author should be able to replace/remove native semantics if needed. This can ruin the web page but it gives the absolute control over the page content. A dangerous but quite powerful tool like atomic energy. ] | ||
===Sniffing=== | ===Sniffing=== | ||
In order to make optimization the content provider has to know whether accessibility consumer is active. The provider can add a callback for <code>deploy</code> and <code>conceal</code> event types which will be triggered when consumer appears/gets inactive. | In order to make an optimization, the content provider has to know whether an accessibility consumer (like screen reader) is active. The provider can add a callback for <code>deploy</code> and <code>conceal</code> event types which will be triggered when consumer appears/gets inactive. | ||
<pre> | <pre> | ||
Line 2,241: | Line 2,226: | ||
sequence<DOMString> states; | sequence<DOMString> states; | ||
Object attributes; | Object attributes; | ||
sequence<DOMString> relations; | |||
sequence<DOMString> actions; | |||
}; | }; | ||
</pre> | </pre> | ||
Line 2,263: | Line 2,250: | ||
RoleTaxon .''attributes'' | RoleTaxon .''attributes'' | ||
::List of attributes supported by the role. Default value of the attribute may be specified as modifier. For example, "live:polite" points out that "live" object attribute has "polite" value by default. If default value is not specified then it's taken from referred attribute taxon description. | ::List of attributes supported by the role. Default value of the attribute may be specified as modifier. For example, "live:polite" points out that "live" object attribute has "polite" value by default. If default value is not specified then it's taken from referred attribute taxon description. | ||
RoleTaxon .''relations'' | |||
::List of relations supported by the role. | |||
RoleTaxon ..''actions'' | |||
::List of supported actions. Actions from the list are exposed on the accessible element depending on states present on it. For example, if supported actions are "check" and "uncheck", then "check" is exposed if the accessible element doesn't have "checked" state, otherwise "unchecked". | |||
</code> | </code> | ||
<b>Example. ARIA <code>textbox</code> role</b> | <b>Example. ARIA <code>textbox</code> role.</b> | ||
<pre> | <pre> | ||
Line 2,287: | Line 2,280: | ||
}; | }; | ||
</pre> | </pre> | ||
<b>Example. ARIA <code>checkbox</code> role.</b> | |||
<pre> | |||
var taxa = { | |||
checkbox: { | |||
description: "checkbox", | |||
parents: [ "input" ], | |||
states: [ "checkable:default, "checked" ], | |||
actions: [ "check", "uncheck" ] | |||
} | |||
}; | |||
</pre> | |||
<b>Example. ARIA <code>log</code> role.</b> | <b>Example. ARIA <code>log</code> role.</b> | ||
Line 2,300: | Line 2,308: | ||
}; | }; | ||
</pre> | </pre> | ||
====States==== | ====States==== | ||
Line 2,308: | Line 2,315: | ||
DOMString description; | DOMString description; | ||
sequence<DOMString> dependents; | sequence<DOMString> dependents; | ||
DOMString | DOMString exclusives; | ||
} | } | ||
</pre> | </pre> | ||
Line 2,320: | Line 2,327: | ||
::List of all dependent states. For example, "focused" state always accompanied by "focusable" state. | ::List of all dependent states. For example, "focused" state always accompanied by "focusable" state. | ||
StateTaxon ..'' | StateTaxon ..''exclusives'' | ||
:: | ::Mutually exclusive states if applicable. For example, if "vertical" state is applied then "horizontal" is not and vice versa. | ||
</code> | </code> | ||
Line 2,333: | Line 2,340: | ||
}, | }, | ||
focused: { }, | focused: { }, | ||
singleline: { | singleline: { | ||
exlcusives: [ "multiline" ] | |||
}, | }, | ||
multiline: { | multiline: { | ||
exlcusives: [ "singleline" ] | |||
}, | }, | ||
readonly: { }, | readonly: { }, | ||
editable: { }, | editable: { }, | ||
required: { } | required: { }, | ||
checked: { | |||
exlusives: [ "mixed" ] | |||
}, | |||
mixed: { | |||
exlusives: [ "checked" ] | |||
} | |||
}; | }; | ||
</pre> | </pre> | ||
====Attributes==== | ====Attributes==== | ||
Line 2,384: | Line 2,399: | ||
</pre> | </pre> | ||
This doc introduces common patterns to express the semantics of markup languages to accessibility. Markup specifics is not a target for this doc in general. Each markup specification has to take care to describe their accessibility stuff in terms of this API. | ====Actions==== | ||
=Extensibility= | <pre> | ||
dictionary ActionTaxon { | |||
DOMString description; | |||
DOMString dual; | |||
sequence<DOMString> states; | |||
}; | |||
</pre> | |||
<code> | |||
ActionTaxon .''description'' | |||
::Localized action description. | |||
ActionTaxon .''dual'' | |||
::Dual action taxon. When action is invoked, it is switched to its dual action if applicable. | |||
ActionTaxon .''states'' | |||
::Implied states. When action is invoked, states of dual action are cleared, this action states are set. | |||
</code> | |||
<b>Example.</b> | |||
<pre> | |||
var taxa = { | |||
check: { | |||
description: "check", | |||
dual: "uncheck", | |||
states: [ "checked" ] | |||
}, | |||
uncheck: { | |||
description: "uncheck", | |||
dual: "check" | |||
} | |||
}; | |||
</pre> | |||
=HTML and beyond= | |||
This doc introduces common patterns to express the semantics of markup languages to accessibility. Markup specifics is not a target for this doc in general. Each markup specification has to take care to describe their accessibility stuff in terms of this API. | |||
=Extensibility= | |||
The web application might need to extend default taxonomies to express the new semantics. For example, the web service publishing music sheets can introduce new characteristics like role, states, etc to describe music sheet content. However the web application should take care to explain new characteristic by extending default taxonomies, i.e. by describing the connection between old and new characteristics. That will resolve any backward compatibility issue, so if the consumer doesn't know about new roles then he can still figure out a closest match it's aware about. For example, if the web app author introduces "x-redbutton' and provides a role taxonomy for it saying this is an extension of 'button' role, then the consumer unfamiliar with 'x-redbutton' role will treat it as a button. | The web application might need to extend default taxonomies to express the new semantics. For example, the web service publishing music sheets can introduce new characteristics like role, states, etc to describe music sheet content. However the web application should take care to explain new characteristic by extending default taxonomies, i.e. by describing the connection between old and new characteristics. That will resolve any backward compatibility issue, so if the consumer doesn't know about new roles then he can still figure out a closest match it's aware about. For example, if the web app author introduces "x-redbutton' and provides a role taxonomy for it saying this is an extension of 'button' role, then the consumer unfamiliar with 'x-redbutton' role will treat it as a button. | ||
Line 2,424: | Line 2,478: | ||
crescendo: [note, ...] a list a notes the crescendo is applied to | crescendo: [note, ...] a list a notes the crescendo is applied to | ||
diminuendo: [note, ...] a list a notes the diminuendo is applied to | diminuendo: [note, ...] a list a notes the diminuendo is applied to | ||
</pre> | |||
Or in terms of taxonomies: | |||
<pre> | |||
document.import("role", { | |||
sheet: { | |||
description: "sheet", | |||
attributes: [ "instrument", "tempo", "clef" ] | |||
}, | |||
note: { | |||
description: "note", | |||
attributes: [ "key", "alteration", "octave", "duration", "effects" ], | |||
relations: [ "crescendo", "diminuendo" ] | |||
} | |||
}); | |||
document.import("attributes", { | |||
instrument: { | |||
description: "instrument type" | |||
}, | |||
tempo: { | |||
description: "tempo" | |||
}, | |||
clef: { | |||
description: "clef" | |||
}, | |||
key: { | |||
description: "key", | |||
values: [ "C", "D", "E", "F", "G", "A", "H" ], | |||
}, | |||
alteration: { | |||
description: "alteration", | |||
values: [ "none", "flat", "sharp" ], | |||
default: "none" | |||
}, | |||
octave: { | |||
description: "octave", | |||
values: [ "contra", "great", "small", "1line", "2line" ], | |||
}, | |||
duration: { | |||
description: "duration" | |||
}, | |||
effects: { | |||
description: "effects" | |||
} | |||
}); | |||
document.import("relations", { | |||
crescendo: { | |||
description: "crescendo" | |||
}, | |||
diminuendo: { | |||
description: "diminuendo" | |||
} | |||
}); | |||
</pre> | </pre> |