Abstract

IndieUI: Events 1.0 is an abstraction between physical, device-specific user interaction events and inferred user intent such as scrolling or changing values. This provides an intermediate layer between device- and modality-specific user interaction events, and the basic user interface functionality used by web applications. IndieUI: Events focuses on granular user interface interactions such as scrolling the view, canceling an action, changing the value of a user input widget, selecting a range, placing focus on an object, etc. Implementing platforms will combine modality-specific user input, user idiosyncratic heuristics to determine the specific corresponding Indie UI event, and send that to the web application in addition to the modality-specific input such as mouse or keyboard events, should applications wish to process it.

See the introduction for background and usage examples.

Status of This Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This is a Working Draft by the IndieUI Working Group (IndieUI WG) of the Web Accessibility Initiative. It contains incremental updates from the previous draft, which are summarized in Appendix B: Substantive, normative changes since the last public working draft. The IndieUI: Events tracker lists open issues and actions, and links to closed issues and actions, which are the basis for most of the previous and upcoming updates; newer issues are tracked in W3C Bugzilla for IndieUI: Events. The Working Group has published use cases and requirements that are expected to be met by this specification; feedback on these is encouraged as well. Also see the IndieUI Overview. A history of changes to IndieUI: Events 1.0 is available.

Feedback on this draft specification is essential to success of the technology. The IndieUI WG asks in particular:

To comment on this document, send email to public-indie-ui-comments@w3.org (comment archive) or file an issue in W3C Bugzilla. Comments are requested by 27 June 2014. In-progress updates to the document may be viewed in the publicly visible editors' draft.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

Table of Contents

1. Introduction

This section is non-normative.

1.1 Background

Scripting usable interfaces can be difficult, especially when one considers that user interface design patterns differ across software platforms, hardware, and locales, and that those interactions can be further customized based on personal preference. Individuals are accustomed to the way the interface works on their own system, and their preferred interface frequently differs from that of the web application author's preferred interface.

For example, web application authors, wishing to intercept a user's intent to "zoom in" on a custom image viewer or map view, need to "listen" for all of the following events:

In addition to the general user interface challenges, custom interfaces often don't take into account users who access web content via assistive technologies that use alternate forms of input such as screen readers, switch interfaces, or speech-based command and control interfaces.

For example, a web page author may script a custom interface to look like a slider (e.g. one styled to look like an HTML "range" input) and behave like a slider when using standard mouse-based input, but there is no standard way for the value of the slider to be controlled programmatically, so the control may not be usable without a mouse or other pointer-based input.

It would be simpler to listen for a normalized request to "zoom in" on the current view, whereby the web application could determine the new scale factor and update its custom view accordingly. Whether through continuous physical events like a scroll wheel or discrete physical events like the keyboard shortcuts, a user could indicate his intent to "zoom in" and the web application author would only need to listen for a single type of event: zoomrequest.

IndieUI Events defines a way for web authors to register for these request events on a leaf node element or on a ancestor element acting as an event delegate. Authors also declaritively define which actions or behaviors a view responds to, and when it is appropriate for browsers to initiate these events.

1.2 Goals

This section is non-normative.

The primary goals of the Events Module specification are declared as the following:

  1. Make it easier for web developers to author consistently usable interfaces that are input-agnostic and independent of a user's particular platform, hardware, locale, and preferences.
  2. Enable every type of control in these interfaces to be programmatically determinable and controllable by both mainstream and alternate forms of user input.

The IndieUI Working Group also hopes to provide a clear path for web developers to smoothly transition from currently existing physical events to IndieUI events, during the period when implementations of IndieUI are incomplete. This will likely be achieved through polyfill implementations in common JavaScript libraries, though such implementations are not a required deliverable of the IndieUI Working Group, and documentation of this development path is not a requirement of this Events Module specification.

1.3 Document Scope

This section is non-normative.

Decisions regarding which specific physical user interactions (keyboard combinations, gestures, speech, etc.) initiate IndieUI events are explicitly listed as out-of-scope in the Working Group charter. User interface interaction patterns should be designed and defined by each operating system, rather than defined as part of any technical specification.

However, this document lists informative examples of certain keyboard and mouse events that may initiate each IndieUI event. They are listed here purely to aid in clarifying the reader's conceptual understanding of each event, as well as illustrating certain UI differences between platforms. These informative examples are primarily limited to keyboard and mouse events, because those physical modalities have been common in software interaction for decades, and their use is familiar to most readers.

For example, it may be common for the ESC key to trigger a "dismissrequest" event to close a dialog on most systems, but the specification does not require the user agent to use any particular physical event. It is an implementation detail, and left for the developers of each platform or assistive technology to determine whether ESC or some other interaction is the most appropriate way to initiate the "dismissrequest" event. As long as there is a documented way for end users to initiate each event, the user agent will be considered a conforming implementation.

1.4 Usage Examples

1.4.1 Dismissing a Modal Dialog

The following example uses a "dismissrequest" event to close or cancel out of a modal application dialog.

Example 1
<!-- Declare which IndieUI event(s) this element receives. -->
<dialog uiactions="dismiss" id="myDialog">
  <!-- Include an optional click trigger for the dismiss action. -->
					  	  <button uitrigger="dismiss"> Cancel </button>
  ... other dialog contents ...
</dialog>

<script type="text/javascript">
  
  var myDialog = document.getElementById("myDialog");
  						
  // At some point during runtime, the handler will be called.
  // For example, if the user presses ESC key while focus is inside the dialog.
  function dismissHandler(e) {
  
    // Cancel and close the dialog. Don't forget to move focus before closing.
    closeDialog(e.receiver); // Event.receiver is a readonly property like Event.target 
    
    // Then cancel the event.
    e.stopPropagation(); // Stop the event from bubbling.
    e.preventDefault(); // Let the UA/AT know the event was intercepted successfully.

  }

  // Register the event at initialization.
  // Either on the receiver itself, or on an ancestor element like the body. 
  myDialog.addEventListener("dismissrequest", dismissHandler);

</script>

1.4.2 Changing the Value of a Custom Slider

The following example uses a "valuechangerequest" event to modify the value of a custom ARIA slider.

This example was cut. It needs to be rewritten once we add support for composite widgets with @uimanipulator (so the slider thumb can update the value via pointer-based events). See ACTION-79.

Example 2

1.5 Backwards-Compatibility

This section is non-normative.

One of the core principles behind UI Change Request Events is that they operate on a backwards-compatible, opt-in basis. In other words, the web application author has to first be aware of these events, then explicitly declare each event receiver and register an event listener, or user agents behave as normal and do not initiate these events.

Change request events do not cause any direct manipulation or mutation of the DOM, and do not have any "default action" in the context of a web view. Instead, the event conveys the user's intent to the web application, and allows the web application to perform the appropriate action on behalf of the user, including making potential changes to the DOM. If a web application is authored to understand the change request event, it can cancel the event, which informs the user agent that the event has been captured and understood. If a web application does not cancel the event, the user agent may attempt fallback behavior or communicate to the user that the input has not been recognized.

2. UI Actions

User interface actions are declared as enumerated token attribute values on an element. Each value corresponds to a specific UI Request Event, and declares the web page author's ability to receive and handle each of the request events initiated by the user agent. In order to receive each request event, authors MUST also register for the event using Element.addEventListener() at this node or higher in the DOM. User agents SHOULD NOT initiate a UI Request Event when the user's point-of-regard is not inside an element with the corresponding defined action.

2.1 The uiactions IDL Attribute

The uiactions attribute of each instance of the Element interface MUST return a DOMTokenList reflecting the uiactions content attribute.

partial interface Element {
    readonly    attribute DOMTokenList uiactions;
};

2.1.1 Attributes

uiactions of type DOMTokenList, readonly
A DOM element attribute whose DOMTokenList value reflects the value of the uiactions content attribute.

This attribute is readonly b/c DOMTokenList values are modified by methods (e.g. el.uiactions.add("pan");) rather than by string assignment (e.g. NOT el.uiactions = "pan";). Need to make sure this is clear for authors.

2.2 The uiactions Content Attribute

Every element may have a uiactions attribute specified, which is necessary to define the receiver of each type of request event. The attribute, if specified, must have a value that is a set of whitespace-separated tokens representing the various actions to which the web application responds on behalf of this element. The actions that an element has assigned to it consists of all the tokens returned when the value of the uiactions attribute is split on whitespace. (Duplicates are ignored.)

User agents MUST reflect the uiactions content attribute in the uiactions IDL attribute.

All uiactions token values

  • collapse
  • delete
  • directionalfocus
  • dismiss
  • expand
  • linearfocus
  • manipulationcancel
  • manipulationchange
  • manipulationend
  • manipulationstart
  • medianext
  • mediapause
  • mediaprevious
  • mediastart
  • mediastop
  • mediatoggle
  • move
  • palettefocus
  • pan
  • redo
  • rotation
  • scroll
  • scrollcancel
  • scrollend
  • scrollmove
  • scrollstart
  • toolbarfocus
  • undo
  • valuechange
  • zoom

We could probably combine the "manipulation*" event types into a single "manipulation" action value. I don't foresee a case where an author would want to receive some, but not all of them, and even if that case exists, the author could just not listen for those specific events. Ditto for the other continuous event sets like scroll*.

Example 3
<!-- Body element is event listener for all events, but event receiver only for "delete" actions. -->
<body uiactions="delete">

  <!-- Element container for custom "mapview" is the event receiver for "pan" and "zoom" actions. -->
  <div id="mapview" uiactions="pan zoom"> ... </div>

  <!-- This Dialog is the event receiver for "dismiss" actions initiated on any lower-level event target. -->
  <dialog uiactions="dismiss"> ... </dialog>

</body>

<script type="text/javascript">
  // Registered all of these on the body as an example of event delegation to help illustrate the difference between event...
  // ...target (document.activeElement or other point-of-regard), receiver (element with defined actions), and listener (body).
  document.body.addEventListener("dismissrequest", handleDismiss);
  document.body.addEventListener("panrequest", handlePan);
  document.body.addEventListener("deleterequest", handleDelete);
  document.body.addEventListener("zoomrequest", handleZoom);
</script>
Note

In the previous example, the "deleterequest" event may be fired any time the user's point-of-regard was inside the document, presumably when the user initiateded their platform's physical event to initiate a deletion, such as pressing the DELETE key. However, the "dismissrequest" would only be fired when the user's point-of-regard was inside the dialog. Likewise, the "panrequest" and "zoomrequest" would only be fired when the user's point-of-regard was inside the map view.

3. UI Triggers

A user interface trigger is an element whose default behavior is to initiate a discrete UIRequestEvent for the current element or an ancestor element.

In order to define a trigger element, authors MUST set the value of the uitrigger attribute as a single token value corresponding to an action defined on the current or an ancestor node. User agents MUST NOT initiate a request Event from a trigger element unless the corresponding action is defined on the current element or an ancester element using the uiactions content attribute or uiactions IDL attribute.

Web authors MUST ensure trigger elements have an appropriate accessible label, as rendered text or a text alternative. Web authors MUST ensure trigger elements use an appropriate implicit or explicit role (usually button).

Web authors SHOULD ensure trigger elements are focusable. Web authors MAY forego making a trigger element focusable if the trigger provides redundant functionality already available through another physical interface. For example, a "delete" trigger may not need to be focusable if pressing the Delete key triggers the same request event.

3.1 The uitrigger IDL Attribute

The uitrigger attribute of each instance of the Element interface MUST return a DOMString reflecting the uitrigger content attribute.

partial interface Element {
                attribute DOMString uitrigger;
};

3.1.1 Attributes

uitrigger of type DOMString,
A DOM element attribute whose DOMString value reflects the value of the uitrigger content attribute.

Consider making this attribute a single DOMToken rather than DOMString; this should be single action token value with whitespace trimmed.

3.2 The uitrigger Content Attribute

Every element may have a uitrigger attribute. The attribute, if specified, must have a value that is a single token representing the UIRequestEvent which should be triggered when this element is clicked or otherwise activated.

User agents MUST reflect the uitrigger content attribute in the uitrigger IDL attribute.

All uitrigger token values

  • collapse
  • delete
  • dismiss
  • expand
  • medianext
  • mediapause
  • mediaprevious
  • mediastart
  • mediastop
  • mediatoggle
  • redo
  • undo
Note

The uitrigger tokens list is a subset of the entire uiactions tokens list. It only lists actions associated with discrete UIRequestEvent types. It does not list actions associated with interfaces that extend UIRequestEvent, such as UIManipulationRequestEvent or UIScrollRequestEvent, because those require additional parameters that cannot be determined by a simple click or activate event on the trigger element.

3.3 Example "Back" Button with Dismiss Request Trigger

The following example demonstrates a view that can be "dismissed" with a "back" button trigger, the ESC key, or other appropriate physical events using a single event handler.

Example 4
<section uiactions="dismiss">
  <!-- "Back" button acts as the dismiss trigger if clicked or activated. -->
  <button uitrigger="dismiss"> Back </button>
  ... other view contents ...
</section>

<script type="text/javascript">
  // A single event handler for a number of user events.
  function handleDismiss(e) {
    // Dismiss the current view.
    dismissView(e.receiver); // Event.receiver is a readonly property like Event.target 
    // Then cancel the event.
    e.stopPropagation(); // Stop the event from bubbling.
    e.preventDefault(); // Let the UA/AT know the event was intercepted successfully.
  }
  document.body.addEventListener("dismissrequest", handleDismiss);
</script>

The single event handler is called when a number of physical events occur:

3.4 Media Player Example with Media Key Triggers

The following example demonstrates a custom media player that uses the same event handler whether a button was activated, a keyboard media key was pressed, or a headphone remote was clicked.

Example 5
<body uiactions="mediaprevious mediatoggle medianext">
  <button uitrigger="mediaprevious"> Previous Track </button>
  <button uitrigger="mediatoggle"> Play/Pause </button>
  <button uitrigger="medianext"> Next Track </button>
</body>

<script type="text/javascript">
  // A single event handler for a number of user events.
  function handleMedia(e) {
    
    // Handle the media events from any physical event source.
    switch (e.type) {
      case "mediapreviousrequest":
        previousTrack();
        break;
      case "mediatogglerequest":
        togglePlayback();
        break;
      case "medianextrequest":
        nextTrack();
        break;
      default:
        return; // Event not handled, so return early to prevent canceling event.
    }

    // Then cancel the event.
    e.stopPropagation(); // Stop the event from bubbling.
    e.preventDefault(); // Let the UA/AT know the event was intercepted successfully.
  }
  
  document.body.addEventListener("mediapreviousrequest", handleMedia);
  document.body.addEventListener("mediatogglerequest", handleMedia);
  document.body.addEventListener("medianextrequest", handleMedia);
</script>

The single event handler is called when a number of physical events occur:

4. UI Manipulators

This section is woefilly incomplete. This is to cover pointer-based manipulation of sub-view elements, like the slider "thumb" inside a slider. Deltas and other details will be included in the request event object.

We may need to extend UIRequestEvent to be a superset of MouseEvent, KeyEvent, FocusEvent, etc. so that we can include all the additional values in the event object.

A user interface manipulator is ... TBD.

In order to define a manipulator element, authors MUST set the value of the manipulator attribute as a single token value corresponding to an action defined on the current or an ancestor node. User agents MUST NOT initiate a request Event from a manipulator element unless the corresponding action is defined on the current element or an ancester element using the uiactions content attribute or uiactions IDL attribute.

4.1 The uimanipulator IDL Attribute

The uimanipulator attribute of each instance of the Element interface MUST return a DOMString reflecting the uimanipulator content attribute.

partial interface Element {
                attribute DOMString uimanipulator;
};

4.1.1 Attributes

uimanipulator of type DOMString,
TBD

4.2 The uimanipulator Content Attribute

TBD

User agents MUST reflect the uimanipulator content attribute in the uimanipulator IDL attribute.

All uimanipulator token values

  • manipulationcancel
  • manipulationchange
  • manipulationend
  • manipulationstart
  • move
  • pan
  • rotation
  • scroll
  • scrollcancel
  • scrollend
  • scrollmove
  • scrollstart
  • valuechange
  • zoom

We could probably combine the "manipulation*" event types into a single "manipulation" action value. I don't foresee a case where an author would want to receive some, but not all of them, and even if that case exists, the author could just not listen for those specific events. Ditto for the other continuous event sets like scroll*.

5. UI Request Events

There is purposefully no request event for activating the default action. Authors are encouraged to use a standard click event for default actions. Update: Eitan (Mozilla) requested ACTION-53: activate request event to augment default action trigger when click handlers are inappropriate.

Event fires on point-of-regard (document.activeElement, clicked element, or AT equivalent) if applicable, or otherwise document.body.

Event order: These events should be asynchronous, but when used in conjunction with keyboard events, we need to define where each IndieUI event fires in the chain of keydown, keyup, and keypress. Probably also need an identifier to associate each event with other related physical events: e.g. This dismissrequest event is associated with the keyboard events keydown, keyup, and keypress of the ESC key.

5.1 Interface UIRequestEvent

Separate interface from UIEvent because the @uiactions attribute will 1) affect when and where these events are fired, and 2) adds the distinction of an event receiver element (element declaring the uiactions attribute) in addition to the "target" element where the event initiates and the "listener" element where the event is registered for and handled.

The receiver attribute of each instance of the UIRequestEvent interface MUST return an EventTarget matching the DOMElement where the corresponding event's action is declared via the uiactions attribute.

[Constructor(DOMString typeArg, optional UIRequestEventInit dictUIRequestEventInit)]
interface UIRequestEvent : UIEvent {
    readonly    attribute EventTarget receiver;
};

5.1.1 Attributes

receiver of type EventTarget, readonly
In addition to the event target, each UI Request Event has a receiver element, which is declared via the uiactions content attribute on an ancestor node of the event target.

5.1.2 Determining the Event Receiver

The event receiver is determined using the following steps:

  1. For each event name literal ("dismissrequest"), determine the corresponding uiactions token ("dismiss").
  2. Starting with the event's target element, determine if the element's actions list contains the corresponding action for the event (el.uiactions.contains("dismiss")). If the current element's action list contains the corresponding uiactions token, the event target is also the event receiver.
  3. If the current element's action list does not contain the corresponding uiactions token, move up to the parent element and try again. Continue until reaching the root element. The closest ancestor to match the corresponding action token is the event receiver.
  4. If the event receiver is still undetermined upon reaching the root element, stop. There is no valid event receiver and the user agent MUST NOT initiate the event.

May also need a way to associate IndieUI events with their physical event counterparts.

[Example]
partial interface UIEvent {
  readonly attribute EventID id; // UID of current event
  readonly attribute EventList relatedEvents; // List of related events, with ID and potentially type of each event. 
  // This "dismissrequest" event is associated with the previous "keydown" and "keyup" events.
}

5.1.3 UIRequestEventInit

dictionary UIRequestEventInit : UIEventInit {
    boolean      bubbles = true;
    boolean      cancelable = true;
    WindowProxy? view = null;
    long         detail = 0;
    EventTarget  receiver = null;
};
5.1.3.1 Dictionary UIRequestEventInit Members
bubbles of type boolean, defaulting to true
cancelable of type boolean, defaulting to true
detail of type long, defaulting to 0
receiver of type EventTarget, defaulting to null
view of type WindowProxy, nullable, defaulting to null

5.1.4 UIRequestEvent Types

The different types of UIRequestEvents that can occur are:

Undo Request (undorequest)

Indicates the user desires to "undo" the previous action.

May be superseded by the UndoManager interface.

  • Bubbles: Yes
  • Cancelable: Yes

Users, wanting to "undo" a discrete action in a web application, can indicate their intent a number of ways, including pressing Control+Z on Windows or Linux, Command+Z on Mac OS X, and even by shaking some accelerometer- or gyroscope-enabled mobile devices.

Redo Request (redorequest)

Indicates the user desires to "redo" the previously "undone" action.

May be superseded by the UndoManager interface.

  • Bubbles: Yes
  • Cancelable: Yes

Users, wanting to "redo" a discrete action in a web application, can indicate their intent a number of ways, including pressing Control+Shift+Z on Windows or Linux, Command+Shift+Z on Mac OS X.

Expand Request (expandrequest)

Indicates the user desires to to reveal information in a collapsed section (e.g. a disclosure widget) or branch node in a hierarchy (e.g., a tree view).

  • Bubbles: Yes
  • Cancelable: Yes
Collapse Request (collapserequest)

Indicates the user desires to hide or collapse information in an expanded section (e.g. a disclosure widget) or branch node in a hierarchy (e.g., a tree view).

  • Bubbles: Yes
  • Cancelable: Yes
Dismiss Request (dismissrequest)

Indicates the user desires "dismiss" the current view (e.g. canceling a dialog, or closing a popup menu).

  • Bubbles: Yes
  • Cancelable: Yes

Users, wanting to "escape from" or "dismiss" a web application state (for example, closing a modal dialog), can indicate their intent a number of ways, most commonly by pressing Escape on keyboard-controlled operating systems. Web authors who have registered for this event should process the event to determine whether to cancel the event. If the "dismiss" action is understood in the context of the web application, web authors should perform the appropriate action (such as closing the dialog), and cancel the event using the event object's preventDefault() method.

Delete Request (deleterequest)

Indicates the user wants to initiate a "delete" action on the marked element or current view.

  • Bubbles: Yes
  • Cancelable: Yes
Pause Media Playback Request (mediapauserequest)

Initiated when the user agent sends a request to the web application to pause media playback.

  • Bubbles: Yes
  • Cancelable: Yes
Start Media Playback Request (mediastartrequest)

Initiated when the user agent sends a request to the web application to start media playback.

  • Bubbles: Yes
  • Cancelable: Yes
Stop Media Playback Request (mediastoprequest)

Initiated when the user agent sends a request to the web application to stop media playback.

  • Bubbles: Yes
  • Cancelable: Yes
Toggle Media Playback Request (mediatogglerequest)

Initiated when the user agent sends a request to the web application to toggle the play/pause state of media playback.

  • Bubbles: Yes
  • Cancelable: Yes
Previous Track Request (mediapreviousrequest)

Initiated when the user agent sends a request to the web application to skip media to the previous track boundary.

  • Bubbles: Yes
  • Cancelable: Yes
Next Track Request (medianextrequest)

Initiated when the user agent sends a request to the web application to skip media to the next track boundary.

  • Bubbles: Yes
  • Cancelable: Yes

There may be a need for continuous media request events to support fast-forward or rewind via press-and-hold, or double-click-and-hold, etc.

5.2 Interface UIFocusRequestEvent

[Constructor(DOMString typeArg, optional UIFocusRequestEventInit dictUIFocusRequestEventInit)]
interface UIFocusRequestEvent : UIRequestEvent {
    readonly    attribute FocusRequestFocusType focusType;
};

5.2.1 Attributes

focusType of type FocusRequestFocusType, readonly

5.2.2 Enumeration FocusRequestFocusType

enum FocusRequestFocusType {
    "none",
    "navFirst",
    "navPrevious",
    "navNext",
    "navLast",
    "navUp",
    "navUpRight",
    "navRight",
    "navDownRight",
    "navDown",
    "navDownLeft",
    "navLeft",
    "navUpLeft"
};
Enumeration description
noneNot applicable. Event is not a linear or directional focus event.
navFirstlinear first
navPreviouslinear previous
navNextlinear next
navLastlinear last
navUpdirectional "North"
navUpRightdirectional "Northeast"
navRightdirectional "East"
navDownRightdirectional "Southeast"
navDowndirectional "South"
navDownLeftdirectional "Southwest"
navLeftdirectional "West"
navUpLeftdirectional "Northwest"

5.2.3 UIFocusRequestEventInit

dictionary UIFocusRequestEventInit : UIRequestEventInit {
    boolean               bubbles = true;
    boolean               cancelable = true;
    WindowProxy?          view = null;
    long                  detail = 0;
    EventTarget           receiver = null;
    FocusRequestFocusType focusType = "NONE";
};
5.2.3.1 Dictionary UIFocusRequestEventInit Members
bubbles of type boolean, defaulting to true
cancelable of type boolean, defaulting to true
detail of type long, defaulting to 0
focusType of type FocusRequestFocusType, defaulting to "NONE"
Type of linear or directional focus requested, as defined in the FocusRequestFocusType enumeration definition. Value remains "NONE" except when used for directionalfocusrequest or linearfocusrequest.
receiver of type EventTarget, defaulting to null
view of type WindowProxy, nullable, defaulting to null

5.2.4 UIFocusRequestEvent Types

FIXME: explain these can cover focus changes when the element to focus is not yet loaded in the DOM or yet focusable (for example, in list or table views where the entire dataset is not displayed), or non-linear focus shortcuts or overrides when linear focus is not possible (for example, jumping directly from a contenteditable region to the editing toolbar, when Tab and Shift+Tab mean other things).

The types of UIFocusRequestEvents that can occur are:

Directional Focus Request (directionalfocusrequest)

Initiated when the user agent sends a "direction focus" request to the web application. Web authors SHOULD NOT use or register for directionalfocusrequest events when standard browser focus and blur events are sufficient. Using these events unnecessarily could result is reduced performance or an other negative user experience.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: focusType (one of directional focusType string)
Note

On most desktop platforms, directional focus may be triggered by keyboard arrow keys. For example, in a spread sheet or other grid-based application, arrow keys allow the user to navigate vertically within a column, or horizontally within a row.

Linear Focus Request (linearfocusrequest)

Initiated when the user agent sends a "linear focus" request to the web application. Web authors SHOULD NOT use or register for linearfocusrequest events when standard browser focus and blur events are sufficient. This event type is only necessary on specialized control types such as data grids where the logical "next" or "previous" element may not be focusable or even in the DOM until requested. Using these events unnecessarily could result is reduced performance or an other negative user experience.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: focusType (one of linear focusType strings)
Note

On most desktop platforms, linear focus may be triggered by Tab (focus next in linear order) and Shift+Tab (focus previous in linear order).

Palette Focus Request (palettefocusrequest)

Initiated when the user agent sends a "palette focus" request to the web application. Web app authors receiving this event SHOULD move focus to the first palette in the web application, or cycle focus between all available palettes.

  • Bubbles: Yes
  • Cancelable: Yes

Will possibly need an ARIA 1.1 or 2.0 role for palette. Note: palettes are sometimes referred to as non-modal dialogs or inspector windows, but not always, and the definition should not include "sometimes." If we can't come up with a less vague definition and common interaction that doesn't trample a native one (ex. Cmd+tilde on Mac), we may have to drop this event.

Toolbar Focus Request (toolbarfocusrequest)

Initiated when the user agent sends a "toolbar focus" request to the web application. Web app authors receiving this event SHOULD move focus to the main toolbar in the web application, or cycle focus between all available toolbars.

  • Bubbles: Yes
  • Cancelable: Yes

5.3 Interface UIManipulationRequestEvent

[Constructor(DOMString typeArg, optional UIManipulationRequestEventInit dictUIManipulationRequestEventInit)]
interface UIManipulationRequestEvent : UIRequestEvent {
    readonly    attribute double? originX;
    readonly    attribute double? originY;
    readonly    attribute double  deltaX;
    readonly    attribute double  deltaY;
    readonly    attribute double  scaleFactor;
    readonly    attribute double  rotation;
};

5.3.1 Attributes

deltaX of type double, readonly
deltaY of type double, readonly
originX of type double, readonly , nullable
originY of type double, readonly , nullable
rotation of type double, readonly
scaleFactor of type double, readonly

5.3.2 UIManipulationRequestEventInit

dictionary UIManipulationRequestEventInit : UIRequestEventInit {
    boolean      bubbles = true;
    boolean      cancelable = true;
    WindowProxy? view = null;
    long         detail = 0;
    EventTarget  receiver = null;
    double?      originX = null;
    double?      originY = null;
    double       deltaX = 0.0;
    double       deltaY = 0.0;
    double       scaleFactor = 1.0;
    double       rotation = 0.0;
};
5.3.2.1 Dictionary UIManipulationRequestEventInit Members
bubbles of type boolean, defaulting to true
cancelable of type boolean, defaulting to true
deltaX of type double, defaulting to 0.0
The cartesian X coordinate delta from the event origin, measured in CSS pixels.
deltaY of type double, defaulting to 0.0
The cartesian Y coordinate delta from the event origin, measured in CSS pixels.
detail of type long, defaulting to 0
originX of type double, nullable, defaulting to null
The cartesian X coordinate origin point (if one exists), measured in CSS pixels from the inside(?) left edge of element border box for the receiver element.
originY of type double, nullable, defaulting to null
The cartesian Y coordinate origin point (if one exists), measured in CSS pixels from the inside(?) top edge of element border box for the receiver element.
receiver of type EventTarget, defaulting to null
rotation of type double, defaulting to 0.0
Rotation value, in degrees from 0. Positive values indicate a counter-clockwise rotation. Negative values indicate a clockwise rotation.
scaleFactor of type double, defaulting to 1.0
Scale factor, used in zoom manipulations, where 1.0 is the original scale factor. For example, a value of 2.0 or 3.0 indicates the element should enlarge to 2 or 3 times its original scale, respectively. A value of 0.5 indicates the element should decrease to one-half its original scale.
view of type WindowProxy, nullable, defaulting to null

5.3.3 Discrete UIManipulationRequestEvent Types

Note

Move and Pan request events are functionally identical, but are specified individually to aid in authoring clarity when using similar concepts like 1) moving an object on a layout canvas, and 2) panning a continuous view like a map.

The discrete types of UIManipulationRequestEvents that can occur are:

Move Request (moverequest)

Initiated when the user agent sends a move request to the web application with accompanying x/y delta values. This is used, for example, when moving an object to a new location on a layout canvas.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: deltaX, deltaY
Pan Request (panrequest)

Initiated when the user agent sends a pan request to the web application with accompanying x/y delta values. This is used, for example, when changing the center point while panning a map or another custom image viewer.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: deltaX, deltaY
Rotation Request (rotationrequest)

Initiated when the user agent sends a rotation request to the web application with accompanying origin x/y values and a rotation value in degrees.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, rotation
Note

In the case where a User Agent lacks a clear or relevant point of origin, user agents could send null values for originX and originY, or they could send x/y coordinates representing the center point of the event.receiver element.

For example, many photo manipulation applications allow users to change orientation, or rotating a photograph 90 degrees, by pressing a key combination like Option+LeftArrow or Option+RightArrow. Since this represents a keyboard only event that is unrelated to the mouse pointer location, it would be appropriate to send null values. In many cases, web applications may not require the origin x/y coordinates for rotation events even if non-null values exist.

Zoom Request (zoomrequest)

Initiated when the user agent sends a zoom request to the web application with accompanying origin x/y values and the zoom scale factor. This may be used, for example, with a map view or custom layout view.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, scaleFactor
Note

Web authors may use originX and originY in the way they deem most appropriate for the context of their application. In most cases, web applications receiving zoomrequest events will center the UI "zoom" on the originX/originY coordinates if they are provided. If origin coordinates are not provided, such as in the case of a keyboard-only zoom event, web authors will likely center the UI "zoom" in the middle of the receiving view.

There may be a need for a combined, continuous manipulation events (e.g. Pan+Zoom simultaneously) in addition to the discrete events listed above, but the following specification ideas are incomplete. For example, we're currently missing a feature to associate related events, and a description of what "canceling" implies.

5.3.4 Continuous UIManipulationRequestEvent Types

These continuous events may need an identifier per manipulation, for example, to associate a manipulationcancelrequest with the originating manipulationstartrequest that needs to be canceled.

The continuous types of UIManipulationRequestEvents that can occur are:

Manipulation Start Request (manipulationstartrequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY, rotation, scaleFactor
Manipulation Change Request (manipulationchangerequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY, rotation, scaleFactor
Manipulation End Request (manipulationendrequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY, rotation, scaleFactor
Manipulation Cancel Request (manipulationcancelrequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY, rotation, scaleFactor

5.4 Interface UIScrollRequestEvent

[Constructor(DOMString typeArg, optional UIScrollRequestEventInit dictUIScrollRequestEventInit)]
interface UIScrollRequestEvent : UIRequestEvent {
    readonly    attribute double?                 deltaX;
    readonly    attribute double?                 deltaY;
    readonly    attribute ScrollRequestScrollType scrollType;
};

5.4.1 Attributes

deltaX of type double, readonly , nullable
deltaY of type double, readonly , nullable
scrollType of type ScrollRequestScrollType, readonly

5.4.2 Enumeration ScrollRequestScrollType

enum ScrollRequestScrollType {
    "deltas",
    "up",
    "right",
    "down",
    "left",
    "pageUp",
    "pageRight",
    "pageDown",
    "pageLeft",
    "limitUp",
    "limitRight",
    "limitDown",
    "limitLeft"
};
Enumeration description
deltasDefault value for scrollType indicating that scroll amount is provided as deltaX and deltaY in CSS pixels.
upEquivalent to the default behavior of the UP key in most native scroll views.
rightEquivalent to the default behavior of the RIGHT key in most native scroll views.
downEquivalent to the default behavior of the DOWN key in most native scroll views.
leftEquivalent to the default behavior of the LEFT key in most native scroll views.
pageUpEquivalent to the default behavior of the PAGEUP key in most native scroll views.
pageRight
pageDownEquivalent to the default behavior of the PAGEDOWN key in most native scroll views.
pageLeft
limitUpEquivalent to the default behavior of the HOME key in most native scroll views.
limitRight
limitDownEquivalent to the default behavior of the END key in most native scroll views.
limitLeft

5.4.3 UIScrollRequestEventInit

dictionary UIScrollRequestEventInit : UIRequestEventInit {
    boolean                 bubbles = true;
    boolean                 cancelable = true;
    WindowProxy?            view = null;
    long                    detail = 0;
    EventTarget             receiver = null;
    double?                 originX = 0.0;
    double?                 originY = 0.0;
    double?                 deltaX = 0.0;
    double?                 deltaY = 0.0;
    ScrollRequestScrollType scrollType = "deltas";
};
5.4.3.1 Dictionary UIScrollRequestEventInit Members
bubbles of type boolean, defaulting to true
cancelable of type boolean, defaulting to true
deltaX of type double, nullable, defaulting to 0.0
The cartesian X coordinate delta from the event origin, measured in CSS pixels.
deltaY of type double, nullable, defaulting to 0.0
The cartesian Y coordinate delta from the event origin, measured in CSS pixels.
detail of type long, defaulting to 0
originX of type double, nullable, defaulting to 0.0
The cartesian X coordinate origin point (if one exists), measured in CSS pixels from the inside(?) left edge of element border box for the receiver element.
originY of type double, nullable, defaulting to 0.0
The cartesian Y coordinate origin point (if one exists), measured in CSS pixels from the inside(?) top edge of element border box for the receiver element.
receiver of type EventTarget, defaulting to null
scrollType of type ScrollRequestScrollType, defaulting to "deltas"
view of type WindowProxy, nullable, defaulting to null

5.4.4 UIScrollRequestEvent Types

The discrete type of UIScrollRequestEvent that can occur is:

Scroll Request (scrollrequest)

Initiated when the user agent sends a scroll request to the web application with accompanying x/y delta values or one of the other defined scrollType values. Authors SHOULD only use this event and uiaction with custom scroll views that cannot be acheieved with native scroll views, because the hardware-accellerated scrolling of native views will always outperform these events.

Need an example here and clarifying text to indicate UAs "must" either send a non-default scrollType, or non-default deltas, but not both.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: scrollType, deltaX, and deltaY

5.4.5 Continuous UIScrollRequestEvent Types

These continuous events may need an identifier per scroll, for example, to associate a scrollcancelrequest with the originating scrollstartrequest that needs to be canceled.

The continuous types of UIScrollRequestEvents that can occur are:

Scroll Start Request (scrollstartrequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY
Scroll Move Request (scrollmoverequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY
Scroll End Request (scrollendrequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY
Scroll Cancel Request (scrollcancelrequest)

TBD

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: originX, originY, deltaX, deltaY

5.5 Interface UIValueChangeRequestEvent

[Constructor(DOMString typeArg, optional UIValueChangeRequestEventInit dictUIValueChangeRequestEventInit)]
interface UIValueChangeRequestEvent : UIRequestEvent {
    readonly    attribute ValueChangeRequestChangeType changeType;
};

5.5.1 Attributes

changeType of type ValueChangeRequestChangeType, readonly

5.5.2 Enumeration ValueChangeRequestChangeType

enum ValueChangeRequestChangeType {
    "unknown",
    "increment",
    "incrementSmall",
    "incrementLarge",
    "incrementMaximum",
    "decrement",
    "decrementSmall",
    "decrementLarge",
    "decrementMinimum"
};
Enumeration description
unknown
incrementEquivalent to the default behavior of the UP key on most native sliders.
incrementSmallEquivalent to the behavior of ALT+UP or OPTION+UP on some native controls, indicating a finely tuned adjustment (e.g. +0.1% as opposed to +1%).
incrementLargeEquivalent to the default behavior of PAGEUP or SHIFT+UP on many native sliders.
incrementMaximumEquivalent to the default behavior of the END key on most native sliders.
decrementEquivalent to the default behavior of the DOWN key on most native sliders.
decrementSmallEquivalent to the behavior of ALT+DOWN or OPTION+DOWN on some native controls, indicating a finely tuned adjustment (e.g. -0.1% as opposed to -1%).
decrementLargeEquivalent to the default behavior of PAGEDOWN or SHIFT+DOWN on many native sliders.
decrementMinimumEquivalent to the default behavior of the HOME key on most native sliders.

5.5.3 UIValueChangeRequestEventInit

dictionary UIValueChangeRequestEventInit : UIRequestEventInit {
    boolean                      bubbles = true;
    boolean                      cancelable = true;
    WindowProxy?                 view = null;
    long                         detail = 0;
    EventTarget                  receiver = null;
    ValueChangeRequestChangeType changeType = "UNKNOWN";
};
5.5.3.1 Dictionary UIValueChangeRequestEventInit Members
bubbles of type boolean, defaulting to true
cancelable of type boolean, defaulting to true
changeType of type ValueChangeRequestChangeType, defaulting to "UNKNOWN"
detail of type long, defaulting to 0
receiver of type EventTarget, defaulting to null
view of type WindowProxy, nullable, defaulting to null

5.5.4 UIValueChangeRequestEvent Types

The single type of UIValueChangeRequestEvent that can occur is:

Value Change Request (valuechangerequest)

Initiated when the user agent sends a value change request to the web application. Used on custom range controls like sliders, carousels, etc.

Web authors MUST code applications to accept all values of the changeType attribute. For example, if there is no special behavior for INCREMENT_SMALL or INCREMENT_LARGE, web applications would behave as if they had received a basic INCREMENT change type.

  • Bubbles: Yes
  • Cancelable: Yes
  • Context Info: changeType

Users, wanting to change the value of a custom range widget (e.g. sliders or carousels) in a web application, can indicate their intent a number of ways, including pressing various keys (Up, Down, Left, Right, PageUp, PageDown, Home, End) on most keyboard-controlled interfaces. User agents understanding this intent should initiate a valuechangerequest event. Web authors who have registered for this event, should process the event to determine whether to cancel the event. If the value change action is understood in the context of the web application, web authors should change the value of the associated widget by an amount determined via the changeType argument, and cancel the event using the event object's preventDefault() method.

6. Feature Detection

This section is non-normative.

Authors wishing to conditionally assign request event handlers based on whether the user agent supports these events can use standard objection detection for each event handler or property.

6.1 Conditionally Assigning a UI Request Event

The following example conditionally assigns a "dismissrequest" event based on whether the user agent has support for the feature.

Example 6
if (typeof document.body.ondismissrequest !== "undefined") {
  // Okay to use "dismissrequest" event.
  document.body.addEventListener("dismissrequest", dismissHandler);
} else {
  // Otherwise catch the ESC key or another platform-specific equivalent event.
  document.body.addEventListener("keyup", keyHandler);
}

Note: need to double-check that the above code sample is really the best approach.

A. Events List (alphabetical)

B. Substantive, normative changes since the last public working draft

C. Glossary

Activated

TBD: define as click or relevant keypress like Enter/Return, and spacebar in some scenarios.

Assistive Technology

TBD

Default Behavior

TBD

Marked Element(s)

TBD. At Risk. Will be defined in conjunction with markrequest, which is covered by ACTION-25, and not yet in the spec.

Point-of-Regard

UIRequestEvents initiate from the element representing the point-of-regard, and are referenced in the Event object's target property.

For mainstream user agents, the point-of-regard will likely be the element under a pointer (e.g. mouse cursor) or, in the case of keyboard events, the currently focused element (e.g. document.activeElement). Assistive technologies or other alternative inputs may determine another element to be the subject of the user's attention, and initiate events from this new point-of-regard.

Still looking for a better term than point-of-regard.

Reflected Attribute

Attributes whose DOM property and content attribute values remain in sync. Identical to reflected attributes in HTML.

Request Event Receiver

The closest DOM ancestor to the user's point-of-regard that declares the current event type via the uiactions content attribute or uiactions DOM attribute. The Request Event Receiver is referenced in the Event object's receiver property.

UI Request Events are not initiated by the user agent unless the following are true:

  1. The user's point of regard is on the current or descendant node of an element that declares the event receiver via @uiactions
  2. The event receiver node (or any ancestor node of the receiver) also registered as the event listener via element.addEventListener()

Some of this definition will need to be massaged and move into the normative sections above defining @uiactions.

User Agent

TBD

D. Acknowledgements

D.1 Active IndieUI Members

At the time of publishing, the following individuals were active, participating members of the IndieUI Working Group.

D.2 Contributors

The following individual(s) were previously active members of the working group or otherwise significant contributors.

Tab Atkins, Jesse Bunch, Chris Fleizach, Lachlan Hunt, Bradley Meck, Sangwhan Moon, Ryosuke Niwa, Rich Simpson.

D.3 Enabling funders

This publication has been funded in part with Federal funds from the U.S. Department of Education, National Institute on Disability and Rehabilitation Research (NIDRR) under contract number ED-OSE-10-C-0067. The content of this publication does not necessarily reflect the views or policies of the U.S. Department of Education, nor does mention of trade names, commercial products, or organizations imply endorsement by the U.S. Government.