HTML 5

Draft Recommendation — 7 July 2008

4.11 Interactive elements

4.11.1 The details element

Categories
Flow content.
Contexts in which this element may be used:
Where flow content is expected.
Content model:
One legend element followed by flow content.
Element-specific attributes:
open
DOM interface:
interface HTMLDetailsElement : HTMLElement {
           attribute boolean open;
};

The details element represents additional information or controls which the user can obtain on demand.

The first element child of a details element, if it is a legend element, represents the summary of the details.

If the first element is not a legend element, the UA should provide its own legend (e.g. "Details").

The open content attribute is a boolean attribute. If present, it indicates that the details should be shown to the user. If the attribute is absent, the details should not be shown.

If the attribute is removed, then the details should be hidden. If the attribute is added, the details should be shown.

The user should be able to request that the details be shown or hidden.

The open attribute must reflect the open content attribute.

Rendering will be described in the Rendering section in due course. Basically CSS :open and :closed match the element, it's a block-level element by default, and when it matches :closed it renders as if it had an XBL binding attached to it whose template was just <template>▶<content includes="legend:first-child">Details</content></template>, and when it's :open it acts as if it had an XBL binding attached to it whose template was just <template>▼<content includes="legend:first-child">Details</content><content/></template> or some such.

Clicking the legend would make it open/close (and would change the content attribute). Question: Do we want the content attribute to reflect the actual state like this? I think we do, the DOM not reflecting state has been a pain in the neck before. But is it semantically ok?

4.11.2 The datagrid element

Categories
Flow content.
Interactive element.
Sectioning root.
Contexts in which this element may be used:
Where flow content is expected.
Content model:
Either: Nothing.
Or: Flow content, but where the first element child node, if any, is not a table, select, or datalist element.
Or: A single table element.
Or: A single select element.
Or: A single datalist element.
Element-specific attributes:
multiple
disabled
DOM interface:
interface HTMLDataGridElement : HTMLElement {
           attribute DataGridDataProvider data;
  readonly attribute DataGridSelection selection;
           attribute boolean multiple;
           attribute boolean disabled;
  void updateEverything();
  void updateRowsChanged(in RowSpecification row, in unsigned long count);
  void updateRowsInserted(in RowSpecification row, in unsigned long count);
  void updateRowsRemoved(in RowSpecification row, in unsigned long count);
  void updateRowChanged(in RowSpecification row);
  void updateColumnChanged(in unsigned long column);
  void updateCellChanged(in RowSpecification row, in unsigned long column);
};

One possible thing to be added is a way to detect when a row/selection has been deleted, activated, etc, by the user (delete key, enter key, etc).

This element is defined as interactive, which means it can't contain other interactive elements, despite the fact that we expect it to work with other interactive elements e.g. checkboxes and input fields. It should be called something like a Leaf Interactive Element or something, which counts for ancestors looking in and not descendants looking out.

The datagrid element represents an interactive representation of tree, list, or tabular data.

The data being presented can come either from the content, as elements given as children of the datagrid element, or from a scripted data provider given by the data DOM attribute.

The multiple and disabled attributes are boolean attributes. Their effects are described in the processing model sections below.

The multiple and disabled DOM attributes must reflect the multiple and disabled content attributes respectively.

4.11.2.1. The datagrid data model

This section is non-normative.

In the datagrid data model, data is structured as a set of rows representing a tree, each row being split into a number of columns. The columns are always present in the data model, although individual columns may be hidden in the presentation.

Each row can have child rows. Child rows may be hidden or shown, by closing or opening (respectively) the parent row.

Rows are referred to by the path along the tree that one would take to reach the row, using zero-based indices. Thus, the first row of a list is row "0", the second row is row "1"; the first child row of the first row is row "0,0", the second child row of the first row is row "0,1"; the fourth child of the seventh child of the third child of the tenth row is "9,2,6,3", etc.

The columns can have captions. Those captions are not considered a row in their own right, they are obtained separately.

Selection of data in a datagrid operates at the row level. If the multiple attribute is present, multiple rows can be selected at once, otherwise the user can only select one row at a time.

The datagrid element can be disabled entirely by setting the disabled attribute.

Columns, rows, and cells can each have specific flags, known as classes, applied to them by the data provider. These classes affect the functionality of the datagrid element, and are also passed to the style system. They are similar in concept to the class attribute, except that they are not specified on elements but are given by scripted data providers.

4.11.2.2. How rows are identified

The chains of numbers that give a row's path, or identifier, are represented by objects that implement the RowSpecification interface.

[NoInterfaceObject] interface RowSpecification {
  // binding-specific interface
};

In ECMAScript, two classes of objects are said to implement this interface: Numbers representing non-negative integers, and homogeneous arrays of Numbers representing non-negative integers. Thus, [1,0,9] is a RowSpecification, as is 1 on its own. However, [1,0.2,9] is not a RowSpecification object, since its second value is not an integer.

User agents must always represent RowSpecifications in ECMAScript by using arrays, even if the path only has one number.

The root of the tree is represented by the empty path; in ECMAScript, this is the empty array ([]). Only the getRowCount() and GetChildAtPosition() methods ever get called with the empty path.

4.11.2.3. The data provider interface

The conformance criteria in this section apply to any implementation of the DataGridDataProvider, including (and most commonly) the content author's implementation(s).

// To be implemented by Web authors as a JS object
[NoInterfaceObject] interface DataGridDataProvider {
  void initialize(in HTMLDataGridElement datagrid);
  unsigned long getRowCount(in RowSpecification row);
  unsigned long getChildAtPosition(in RowSpecification parentRow, in unsigned long position);
  unsigned long getColumnCount();
  DOMString getCaptionText(in unsigned long column);
  void getCaptionClasses(in unsigned long column, in DOMTokenList classes);
  DOMString getRowImage(in RowSpecification row);
  HTMLMenuElement getRowMenu(in RowSpecification row);
  void getRowClasses(in RowSpecification row, in DOMTokenList classes);
  DOMString getCellData(in RowSpecification row, in unsigned long column);
  void getCellClasses(in RowSpecification row, in unsigned long column, in DOMTokenList classes);
  void toggleColumnSortState(in unsigned long column);
  void setCellCheckedState(in RowSpecification row, in unsigned long column, in long state);
  void cycleCell(in RowSpecification row, in unsigned long column);
  void editCell(in RowSpecification row, in unsigned long column, in DOMString data);
};

The DataGridDataProvider interface represents the interface that objects must implement to be used as custom data views for datagrid elements.

Not all the methods are required. The minimum number of methods that must be implemented in a useful view is two: the getRowCount() and getCellData() methods.

Once the object is written, it must be hooked up to the datagrid using the data DOM attribute.

The following methods may be usefully implemented:

initialize(datagrid)
Called by the datagrid element (the one given by the datagrid argument) after it has first populated itself. This would typically be used to set the initial selection of the datagrid element when it is first loaded. The data provider could also use this method call to register a select event handler on the datagrid in order to monitor selection changes.
getRowCount(row)
Must return the number of rows that are children of the specified row, including rows that are off-screen. If row is empty, then the number of rows at the top level must be returned. If the value that this method would return for a given row changes, the relevant update methods on the datagrid must be called first. Otherwise, this method must always return the same number. For a list (as opposed to a tree), this method must return 0 whenever it is called with a row identifier that is not empty.
getChildAtPosition(parentRow, position)
Must return the index of the row that is a child of parentRow and that is to be positioned as the positionth row under parentRow when rendering the children of parentRow. If parentRow is empty, then position refers to the positionth row at the top level of the data grid. May be omitted if the rows are always to be sorted in the natural order. (The natural order is the one where the method always returns position.) For a given parentRow, this method must never return the same value for different values of position. The returned value x must be in the range 0 ≤ x < n, where n is the value returned by getRowCount(parentRow).
getColumnCount()
Must return the number of columns currently in the data model (including columns that might be hidden). May be omitted if there is only one column. If the value that this method would return changes, the datagrid's updateEverything() method must be called.
getCaptionText(column)
Must return the caption, or label, for column column. May be omitted if the columns have no captions. If the value that this method would return changes, the datagrid's updateColumnChanged() method must be called with the appropriate column index.
getCaptionClasses(column, classes)
Must add the classes that apply to column column to the classes object. May be omitted if the columns have no special classes. If the classes that this method would add changes, the datagrid's updateColumnChanged() method must be called with the appropriate column index. Some classes have predefined meanings.
getRowImage(row)
Must return a URL giving the address of an image that represents row row, or the empty string if there is no applicable image. May be omitted if no rows have associated images. If the value that this method would return changes, the datagrid's update methods must be called to update the row in question.
getRowMenu(row)
Must return an HTMLMenuElement object that is to be used as a context menu for row row, or null if there is no particular context menu. May be omitted if none of the rows have a special context menu. As this method is called immediately before showing the menu in question, no precautions need to be taken if the return value of this method changes.
getRowClasses(row, classes)
Must add the classes that apply to row row to the classes object. May be omitted if the rows have no special classes. If the classes that this method would add changes, the datagrid's update methods must be called to update the row in question. Some classes have predefined meanings.
getCellData(row, column)
Must return the value of the cell on row row in column column. For text cells, this must be the text to show for that cell. For progress bar cells, this must be either a floating point number in the range 0.0 to 1.0 (converted to a string representation), indicating the fraction of the progress bar to show as full (1.0 meaning complete), or the empty string, indicating an indeterminate progress bar. If the value that this method would return changes, the datagrid's update methods must be called to update the rows that changed. If only one cell changed, the updateCellChanged() method may be used.
getCellClasses(row, column, classes)
Must add the classes that apply to the cell on row row in column column to the classes object. May be omitted if the cells have no special classes. If the classes that this method would add changes, the datagrid's update methods must be called to update the rows or cells in question. Some classes have predefined meanings.
toggleColumnSortState(column)
Called by the datagrid when the user tries to sort the data using a particular column column. The data provider must update its state so that the GetChildAtPosition() method returns the new order, and the classes of the columns returned by getCaptionClasses() represent the new sort status. There is no need to tell the datagrid that it the data has changed, as the datagrid automatically assumes that the entire data model will need updating.
setCellCheckedState(row, column, state)
Called by the datagrid when the user changes the state of a checkbox cell on row row, column column. The checkbox should be toggled to the state given by state, which is a positive integer (1) if the checkbox is to be checked, zero (0) if it is to be unchecked, and a negative number (−1) if it is to be set to the indeterminate state. There is no need to tell the datagrid that the cell has changed, as the datagrid automatically assumes that the given cell will need updating.
cycleCell(row, column)
Called by the datagrid when the user changes the state of a cyclable cell on row row, column column. The data provider should change the state of the cell to the new state, as appropriate. There is no need to tell the datagrid that the cell has changed, as the datagrid automatically assumes that the given cell will need updating.
editCell(row, column, data)
Called by the datagrid when the user edits the cell on row row, column column. The new value of the cell is given by data. The data provider should update the cell accordingly. There is no need to tell the datagrid that the cell has changed, as the datagrid automatically assumes that the given cell will need updating.

The following classes (for rows, columns, and cells) may be usefully used in conjunction with this interface:

Class name Applies to Description
checked Cells The cell has a checkbox and it is checked. (The cyclable and progress classes override this, though.)
cyclable Cells The cell can be cycled through multiple values. (The progress class overrides this, though.)
editable Cells The cell can be edited. (The cyclable, progress, checked, unchecked and indeterminate classes override this, though.)
header Rows The row is a heading, not a data row.
indeterminate Cells The cell has a checkbox, and it can be set to an indeterminate state. If neither the checked nor unchecked classes are present, then the checkbox is in that state, too. (The cyclable and progress classes override this, though.)
initially-hidden Columns The column will not be shown when the datagrid is initially rendered. If this class is not present on the column when the datagrid is initially rendered, the column will be visible if space allows.
initially-closed Rows The row will be closed when the datagrid is initially rendered. If neither this class nor the initially-open class is present on the row when the datagrid is initially rendered, the initial state will depend on platform conventions.
initially-open Rows The row will be opened when the datagrid is initially rendered. If neither this class nor the initially-closed class is present on the row when the datagrid is initially rendered, the initial state will depend on platform conventions.
progress Cells The cell is a progress bar.
reversed Columns If the cell is sorted, the sort direction is descending, instead of ascending.
selectable-separator Rows The row is a normal, selectable, data row, except that instead of having data, it only has a separator. (The header and separator classes override this, though.)
separator Rows The row is a separator row, not a data row. (The header class overrides this, though.)
sortable Columns The data can be sorted by this column.
sorted Columns The data is sorted by this column. Unless the reversed class is also present, the sort direction is ascending.
unchecked Cells The cell has a checkbox and, unless the checked class is present as well, it is unchecked. (The cyclable and progress classes override this, though.)
4.11.2.4. The default data provider

The user agent must supply a default data provider for the case where the datagrid's data attribute is null. It must act as described in this section.

The behavior of the default data provider depends on the nature of the first element child of the datagrid.

While the first element child is a table element

getRowCount(row): The number of rows returned by the default data provider for the root of the tree (when row is empty) must be the total number of tr elements that are children of tbody elements that are children of the table, if there are any such child tbody elements. If there are no such tbody elements then the number of rows returned for the root must be the number of tr elements that are children of the table.

When row is not empty, the number of rows returned must be zero.

The table-based default data provider cannot represent a tree.

Rows in thead elements do not contribute to the number of rows returned, although they do affect the columns and column captions. Rows in tfoot elements are ignored completely by this algorithm.

getChildAtPosition(row, i): The default data provider must return the mapping appropriate to the current sort order.

getColumnCount(): The number of columns returned must be the number of td element children in the first tr element child of the first tbody element child of the table, if there are any such tbody elements. If there are no such tbody elements, then it must be the number of td element children in the first tr element child of the table, if any, or otherwise 1. If the number that would be returned by these rules is 0, then 1 must be returned instead.

getCaptionText(i): If the table has no thead element child, or if its first thead element child has no tr element child, the default data provider must return the empty string for all captions. Otherwise, the value of the textContent attribute of the ith th element child of the first tr element child of the first thead element child of the table element must be returned. If there is no such th element, the empty string must be returned.

getCaptionClasses(i, classes): If the table has no thead element child, or if its first thead element child has no tr element child, the default data provider must not add any classes for any of the captions. Otherwise, each class in the class attribute of the ith th element child of the first tr element child of the first thead element child of the table element must be added to the classes. If there is no such th element, no classes must be added. The user agent must then:

  1. Remove the sorted and reversed classes.
  2. If the table element has a class attribute that includes the sortable class, add the sortable class.
  3. If the column is the one currently being used to sort the data, add the sorted class.
  4. If the column is the one currently being used to sort the data, and it is sorted in descending order, add the reversed class as well.

The various row- and cell- related methods operate relative to a particular element, the element of the row or cell specified by their arguments.

For rows: Since the default data provider for a table always returns 0 as the number of children for any row other than the root, the path to the row passed to these methods will always consist of a single number. In the prose below, this number is referred to as i.

If the table has tbody element children, the element for the ith row is the ith tr element that is a child of a tbody element that is a child of the table element. If the table does not have tbody element children, then the element for the ith real row is the ith tr element that is a child of the table element.

For cells: Given a row and its element, the row's ith cell's element is the ith td element child of the row element.

The colspan and rowspan attributes are ignored by this algorithm.

getRowImage(i): The URL of the row's image is the absolute URL obtained by resolving the value of the src attribute of the first img element child of the row's first cell's element, if there is one and resolving its attribute is successful. Otherwise, the URL of the row's image is the empty string.

getRowMenu(i): If the row's first cell's element has a menu element child, then the row's menu is the first menu element child of the row's first cell's element. Otherwise, the row has no menu.

getRowClasses(i, classes): The default data provider must never add a class to the row's classes.

toggleColumnSortState(i): If the data is already being sorted on the given column, then the user agent must change the current sort mapping to be the inverse of the current sort mapping; if the sort order was ascending before, it is now descending, otherwise it is now ascending. Otherwise, if the current sort column is another column, or the data model is currently not sorted, the user agent must create a new mapping, which maps rows in the data model to rows in the DOM so that the rows in the data model are sorted by the specified column, in ascending order. (Which sort comparison operator to use is left up to the UA to decide.)

When the sort mapping is changed, the values returned by the getChildAtPosition() method for the default data provider will change appropriately.

getCellData(i, j), getCellClasses(i, j, classes), getCellCheckedState(i, j, state), cycleCell(i, j), and editCell(i, j, data): See the common definitions below.

The data provider must call the datagrid's update methods appropriately whenever the descendants of the datagrid mutate. For example, if a tr is removed, then the updateRowsRemoved() methods would probably need to be invoked, and any change to a cell or its descendants must cause the cell to be updated. If the table element stops being the first child of the datagrid, then the data provider must call the updateEverything() method on the datagrid. Any change to a cell that is in the column that the data provider is currently using as its sort column must also cause the sort to be reperformed, with a call to updateEverything() if the change did affect the sort order.

While the first element child is a select or datalist element

The default data provider must return 1 for the column count, the empty string for the column's caption, and must not add any classes to the column's classes.

For the rows, assume the existence of a node filter view of the descendants of the first element child of the datagrid element (the select or datalist element), that skips all nodes other than optgroup and option elements, as well as any descendents of any option elements.

Given a path row, the corresponding element is the one obtained by drilling into the view, taking the child given by the path each time.

Given the following XML markup:

<datagrid>
 <select>
  <!-- the options and optgroups have had their labels and values removed
       to make the underlying structure clearer -->
  <optgroup>
   <option/>
   <option/>
  </optgroup>
  <optgroup>
   <option/>
   <optgroup id="a">
    <option/>
    <option/>
    <bogus/>
    <option id="b"/>
   </optgroup>
   <option/>
  </optgroup>
 </select>
</datagrid>

The path "1,1,2" would select the element with ID "b". In the filtered view, the text nodes, comment nodes, and bogus elements are ignored; so for instance, the element with ID "a" (path "1,1") has only 3 child nodes in the view.

getRowCount(row) must drill through the view to find the element corresponding to the method's argument, and return the number of child nodes in the filtered view that the corresponding element has. (If the row is empty, the corresponding element is the select element at the root of the filtered view.)

getChildAtPosition(row, position) must return position. (The select/datalist default data provider does not support sorting the data grid.)

getRowImage(i) must return the empty string, getRowMenu(i) must return null.

getRowClasses(row, classes) must add the classes from the following list to classes when their condition is met:

The getCellData(row, cell) method must return the value of the label attribute if the row's corresponding element is an optgroup element, otherwise, if the row's corresponding element is an optionelement, its label attribute if it has one, otherwise the value of its textContent DOM attribute.

The getCellClasses(row, cell, classes) method must add no classes.

autoselect some rows when initialized, reflect the selection in the select, reflect the multiple attribute somehow.

The data provider must call the datagrid's update methods appropriately whenever the descendants of the datagrid mutate.

While the first element child is another element

The default data provider must return 1 for the column count, the empty string for the column's caption, and must not add any classes to the column's classes.

For the rows, assume the existence of a node filter view of the descendants of the datagrid that skips all nodes other than li, h1h6, and hr elements, and skips any descendants of menu elements.

Given this view, each element in the view represents a row in the data model. The element corresponding to a path row is the one obtained by drilling into the view, taking the child given by the path each time. The element of the row of a particular method call is the element given by drilling into the view along the path given by the method's arguments.

getRowCount(row) must return the number of child elements in this view for the given row, or the number of elements at the root of the view if the row is empty.

In the following example, the elements are identified by the paths given by their child text nodes:

<datagrid>
 <ol>
  <li> row 0 </li>
  <li> row 1
   <ol>
    <li> row 1,0 </li>
   </ol>
  </li>
  <li> row 2 </li>
 </ol>
</datagrid>

In this example, only the li elements actually appear in the data grid; the ol element does not affect the data grid's processing model.

getChildAtPosition(row, position) must return position. (The generic default data provider does not support sorting the data grid.)

getRowImage(i) must return the absolute URL obtained from resolving the value of the src attribute of the first img element descendant (in the real DOM) of the row's element, that is not also a descendant of another element in the filtered view that is a descendant of the row's element, if such an element exists and resolving its attribute is successful. Otherwise, it must return the empty string.

In the following example, the row with path "1,0" returns "http://example.com/a" as its image URL, and the other rows (including the row with path "1") return the empty string:

<datagrid>
 <ol>
  <li> row 0 </li>
  <li> row 1
   <ol>
    <li> row 1,0 <img src="http://example.com/a" alt=""> </li>
   </ol>
  </li>
  <li> row 2 </li>
 </ol>
</datagrid>

getRowMenu(i) must return the first menu element descendant (in the real DOM) of the row's element, that is not also a descendant of another element in the filtered view that is a descendant of the row's element. (This is analogous to the image case above.)

getRowClasses(i, classes) must add the classes from the following list to classes when their condition is met:

The getCellData(i, j), getCellClasses(i, j, classes), getCellCheckedState(i, j, state), cycleCell(i, j), and editCell(i, j, data) methods must act as described in the common definitions below, treating the row's element as being the cell's element.

selection handling?

The data provider must call the datagrid's update methods appropriately whenever the descendants of the datagrid mutate.

Otherwise, while there is no element child

The data provider must return 0 for the number of rows, 1 for the number of columns, the empty string for the first column's caption, and must add no classes when asked for that column's classes. If the datagrid's child list changes such that there is a first element child, then the data provider must call the updateEverything() method on the datagrid.

4.11.2.4.1. Common default data provider method definitions for cells

These definitions are used for the cell-specific methods of the default data providers (other than in the select/datalist case). How they behave is based on the contents of an element that represents the cell given by their first two arguments. Which element that is is defined in the previous section.

Cyclable cells

If the first element child of a cell's element is a select element that has a no multiple attribute and has at least one option element descendent, then the cell acts as a cyclable cell.

The "current" option element is the selected option element, or the first option element if none is selected.

The getCellData() method must return the textContent of the current option element (the label attribute is ignored in this context as the optgroups are not displayed).

The getCellClasses() method must add the cyclable class and then all the classes of the current option element.

The cycleCell() method must change the selection of the select element such that the next option element after the current option element is the only one that is selected (in tree order). If the current option element is the last option element descendent of the select, then the first option element descendent must be selected instead.

The setCellCheckedState() and editCell() methods must do nothing.

Progress bar cells

If the first element child of a cell's element is a progress element, then the cell acts as a progress bar cell.

The getCellData() method must return the value returned by the progress element's position DOM attribute.

The getCellClasses() method must add the progress class.

The setCellCheckedState(), cycleCell(), and editCell() methods must do nothing.

Checkbox cells

If the first element child of a cell's element is an input element that has a type attribute with the value checkbox, then the cell acts as a check box cell.

The getCellData() method must return the textContent of the cell element.

The getCellClasses() method must add the checked class if the input element is checked, and the unchecked class otherwise.

The setCellCheckedState() method must set the input element's checkbox state to checked if the method's third argument is 1, and to unchecked otherwise.

The cycleCell() and editCell() methods must do nothing.

Editable cells

If the first element child of a cell's element is an input element that has a type attribute with the value text or that has no type attribute at all, then the cell acts as an editable cell.

The getCellData() method must return the value of the input element.

The getCellClasses() method must add the editable class.

The editCell() method must set the input element's value DOM attribute to the value of the third argument to the method.

The setCellCheckedState() and cycleCell() methods must do nothing.

4.11.2.5. Populating the datagrid element

A datagrid must be disabled until its end tag has been parsed (in the case of a datagrid element in the original document markup) or until it has been inserted into the document (in the case of a dynamically created element). After that point, the element must fire a single load event at itself, which doesn't bubble and cannot be canceled.

The end-tag parsing thing should be moved to the parsing section.

The datagrid must then populate itself using the data provided by the data provider assigned to the data DOM attribute. After the view is populated (using the methods described below), the datagrid must invoke the initialize() method on the data provider specified by the data attribute, passing itself (the HTMLDataGridElement object) as the only argument.

When the data attribute is null, the datagrid must use the default data provider described in the previous section.

To obtain data from the data provider, the element must invoke methods on the data provider object in the following ways:

To determine the total number of columns
Invoke the getColumnCount() method with no arguments. The return value is the number of columns. If the return value is zero or negative, not an integer, or simply not a numeric type, or if the method is not defined, then 1 must be used instead.
To get the captions to use for the columns
Invoke the getCaptionText() method with the index of the column in question. The index i must be in the range 0 ≤ i < N, where N is the total number of columns. The return value is the string to use when referring to that column. If the method returns null or the empty string, the column has no caption. If the method is not defined, then none of the columns have any captions.
To establish what classes apply to a column
Invoke the getCaptionClasses() method with the index of the column in question, and an object implementing the DOMTokenList interface, associated with an anonymous empty string. The index i must be in the range 0 ≤ i < N, where N is the total number of columns. The tokens contained in the string underlying DOMTokenList object when the method returns represent the classes that apply to the given column. If the method is not defined, no classes apply to the column.
To establish whether a column should be initially included in the visible columns
Check whether the initially-hidden class applies to the column. If it does, then the column should not be initially included; if it does not, then the column should be initially included.
To establish whether the data can be sorted relative to a particular column
Check whether the sortable class applies to the column. If it does, then the user should be able to ask the UA to display the data sorted by that column; if it does not, then the user agent must not allow the user to ask for the data to be sorted by that column.
To establish if a column is a sorted column
If the user agent can handle multiple columns being marked as sorted simultaneously: Check whether the sorted class applies to the column. If it does, then that column is the sorted column, otherwise it is not.
If the user agent can only handle one column being marked as sorted at a time: Check each column in turn, starting with the first one, to see whether the sorted class applies to that column. The first column that has that class, if any, is the sorted column. If none of the columns have that class, there is no sorted column.
To establish the sort direction of a sorted column
Check whether the reversed class applies to the column. If it does, then the sort direction is descending (down; first rows have the highest values), otherwise it is ascending (up; first rows have the lowest values).
To determine the total number of rows
Determine the number of rows for the root of the data grid, and determine the number of child rows for each open row. The total number of rows is the sum of all these numbers.
To determine the number of rows for the root of the data grid
Invoke the getRowCount() method with a RowSpecification object representing the empty path as its only argument. The return value is the number of rows at the top level of the data grid. If the return value of the method is negative, not an integer, or simply not a numeric type, or if the method is not defined, then zero must be used instead.
To determine the number of child rows for a row
Invoke the getRowCount() method with a RowSpecification object representing the path to the row in question. The return value is the number of child rows for the given row. If the return value of the method is negative, not an integer, or simply not a numeric type, or if the method is not defined, then zero must be used instead.
To determine what order to render rows in

Invoke the getChildAtPosition() method with a RowSpecification object representing the path to the parent of the rows that are being rendered as the first argument, and the position that is being rendered as the second argument. The return value is the index of the row to render in that position.

If the rows are:

  1. Row "0"
    1. Row "0,0"
    2. Row "0,1"
  2. Row "1"
    1. Row "1,0"
    2. Row "1,1"

...and the getChildAtPosition() method is implemented as follows:

function getChildAtPosition(parent, child) {
  // always return the reverse order
  return getRowCount(parent)-child-1;
}

...then the rendering would actually be:

  1. Row "1"
    1. Row "1,1"
    2. Row "1,0"
  2. Row "0"
    1. Row "0,1"
    2. Row "0,0"

If the return value of the method is negative, larger than the number of rows that the getRowCount() method reported for that parent, not an integer, or simply not a numeric type, then the entire data grid should be disabled. Similarly, if the method returns the same value for two or more different values for the second argument (with the same first argument, and assuming that the data grid hasn't had relevant update methods invoked in the meantime), then the data grid should be disabled. Instead of disabling the data grid, the user agent may act as if the getChildAtPosition() method was not defined on the data provider (thus disabling sorting for that data grid, but still letting the user interact with the data). If the method is not defined, then the return value must be assumed to be the same as the second argument (an identity transform; the data is rendered in its natural order).

To establish what classes apply to a row
Invoke the getRowClasses() method with a RowSpecification object representing the row in question, and a DOMTokenList associated with an empty string. The tokens contained in the DOMTokenList object's underlying string when the method returns represent the classes that apply to the row in question. If the method is not defined, no classes apply to the row.
To establish whether a row is a data row or a special row
Examine the classes that apply to the row. If the header class applies to the row, then it is not a data row, it is a subheading. The data from the first cell of the row is the text of the subheading, the rest of the cells must be ignored. Otherwise, if the separator class applies to the row, then in the place of the row, a separator should be shown. Otherwise, if the selectable-separator class applies to the row, then the row should be a data row, but represented as a separator. (The difference between a separator and a selectable-separator is that the former is not an item that can be actually selected, whereas the second can be selected and thus has a context menu that applies to it, and so forth.) For both kinds of separator rows, the data of the rows' cells must all be ignored. If none of those three classes apply then the row is a simple data row.
To establish whether a row is openable
Determine the number of child rows for that row. If there are one or more child rows, then the row is openable.
To establish whether a row should be initially open or closed
If the row is openable, examine the classes that apply to the row. If the initially-open class applies to the row, then it should be initially open. Otherwise, if the initially-closed class applies to the row, then it must be initially closed. Otherwise, if neither class applies to the row, or if the row is not openable, then the initial state of the row should be based on platform conventions.
To obtain a URL identifying an image representing a row
Invoke the getRowImage() method with a RowSpecification object representing the row in question. The return value is a URL. Immediately resolve that URL as if it came from an attribute of the datagrid element to obtain an absolute URL identifying the image that represents the row. If the method returns the empty string, null, or if the method is not defined, then the row has no associated image.
To obtain a context menu appropriate for a particular row
Invoke the getRowMenu() method with a RowSpecification object representing the row in question. The return value is a reference to an object implementing the HTMLMenuElement interface, i.e. a menu element DOM node. (This element must then be interpreted as described in the section on context menus to obtain the actual context menu to use.) If the method returns something that is not an HTMLMenuElement, or if the method is not defined, then the row has no associated context menu. User agents may provide their own default context menu, and may add items to the author-provided context menu. For example, such a menu could allow the user to change the presentation of the datagrid element.
To establish the value of a particular cell
Invoke the getCellData() method with the first argument being a RowSpecification object representing the row of the cell in question and the second argument being the index of the cell's column. The second argument must be a non-negative integer less than the total number of columns. The return value is the value of the cell. If the return value is null or the empty string, or if the method is not defined, then the cell has no data. (For progress bar cells, the cell's value must be further interpreted, as described below.)
To establish what classes apply to a cell
Invoke the getCellClasses() method with the first argument being a RowSpecification object representing the row of the cell in question, the second argument being the index of the cell's column, and the third being an object implementing the DOMTokenList interface, associated with an empty string. The second argument must be a non-negative integer less than the total number of columns. The tokens contained in the DOMTokenList object's underlying string when the method returns represent the classes that apply to that cell. If the method is not defined, no classes apply to the cell.
To establish how the type of a cell
Examine the classes that apply to the cell. If the progress class applies to the cell, it is a progress bar. Otherwise, if the cyclable class applies to the cell, it is a cycling cell whose value can be cycled between multiple states. Otherwise, none of these classes apply, and the cell is a simple text cell.
To establish the value of a progress bar cell
If the value x of the cell is a string that can be converted to a floating-point number in the range 0.0 ≤ x ≤ 1.0, then the progress bar has that value (0.0 means no progress, 1.0 means complete). Otherwise, the progress bar is an indeterminate progress bar.
To establish how a simple text cell should be presented
Check whether one of the checked, unchecked, or indeterminate classes applies to the cell. If any of these are present, then the cell has a checkbox, otherwise none are present and the cell does not have a checkbox. If the cell has no checkbox, check whether the editable class applies to the cell. If it does, then the cell value is editable, otherwise the cell value is static.
To establish the state of a cell's checkbox, if it has one
Check whether the checked class applies to the cell. If it does, the cell is checked. Otherwise, check whether the unchecked class applies to the cell. If it does, the cell is unchecked. Otherwise, the indeterminate class applies to the cell and the cell's checkbox is in an indeterminate state. When the indeterminate class applies to the cell, the checkbox is a tristate checkbox, and the user can set it to the indeterminate state. Otherwise, only the checked and/or unchecked classes apply to the cell, and the cell can only be toggled between those two states.

If the data provider ever raises an exception while the datagrid is invoking one of its methods, the datagrid must act, for the purposes of that particular method call, as if the relevant method had not been defined.

A RowSpecification object p with n path components passed to a method of the data provider must fulfill the constraint 0 ≤ pi < m-1 for all integer values of i in the range 0 ≤ i < n-1, where m is the value that was last returned by the getRowCount() method when it was passed the RowSpecification object q with i-1 items, where pi = qi for all integer values of i in the range 0 ≤ i < n-1, with any changes implied by the update methods taken into account.

The data model is considered stable: user agents may assume that subsequent calls to the data provider methods will return the same data, until one of the update methods is called on the datagrid element. If a user agent is returned inconsistent data, for example if the number of rows returned by getRowCount() varies in ways that do not match the calls made to the update methods, the user agent may disable the datagrid. User agents that do not disable the datagrid in inconsistent cases must honor the most recently returned values.

User agents may cache returned values so that the data provider is never asked for data that could contradict earlier data. User agents must not cache the return value of the getRowMenu method.

The exact algorithm used to populate the data grid is not defined here, since it will differ based on the presentation used. However, the behavior of user agents must be consistent with the descriptions above. For example, it would be non-conformant for a user agent to make cells have both a checkbox and be editable, as the descriptions above state that cells that have a checkbox cannot be edited.

4.11.2.6. Updating the datagrid

Whenever the data attribute is set to a new value, the datagrid must clear the current selection, remove all the displayed rows, and plan to repopulate itself using the information from the new data provider at the earliest opportunity.

There are a number of update methods that can be invoked on the datagrid element to cause it to refresh itself in slightly less drastic ways:

When the updateEverything() method is called, the user agent must repopulate the entire datagrid. If the number of rows decreased, the selection must be updated appropriately. If the number of rows increased, the new rows should be left unselected.

When the updateRowsChanged(row, count) method is called, the user agent must refresh the rendering of the rows starting from the row specified by row, and including the count next siblings of the row (or as many next siblings as it has, if that is less than count), including all descendant rows.

When the updateRowsInserted(row, count) method is called, the user agent must assume that count new rows have been inserted, such that the first new row is identified by row. The user agent must update its rendering and the selection accordingly. The new rows should not be selected.

When the updateRowsRemoved(row, count) method is called, the user agent must assume that count rows have been removed starting from the row that used to be identifier by row. The user agent must update its rendering and the selection accordingly.

The updateRowChanged(row) method must be exactly equivalent to calling updateRowsChanged(row, 1).

When the updateColumnChanged(column) method is called, the user agent must refresh the rendering of the specified column column, for all rows.

When the updateCellChanged(row, column) method is called, the user agent must refresh the rendering of the cell on row row, in column column.

Any effects the update methods have on the datagrid's selection is not considered a change to the selection, and must therefore not fire the select event.

These update methods should be called only by the data provider, or code acting on behalf of the data provider. In particular, calling the updateRowsInserted() and updateRowsRemoved() methods without actually inserting or removing rows from the data provider is likely to result in inconsistent renderings, and the user agent is likely to disable the data grid.

4.11.2.7. Requirements for interactive user agents

This section only applies to interactive user agents.

If the datagrid element has a disabled attribute, then the user agent must disable the datagrid, preventing the user from interacting with it. The datagrid element should still continue to update itself when the data provider signals changes to the data, though. Obviously, conformance requirements stating that datagrid elements must react to users in particular ways do not apply when one is disabled.

If a row is openable, then the user should be able to toggle its open/closed state. When a row's open/closed state changes, the user agent must update the rendering to match the new state.

If a cell is a cell whose value can be cycled between multiple states, then the user must be able to activate the cell to cycle its value. When the user activates this "cycling" behavior of a cell, then the datagrid must invoke the data provider's cycleCell() method, with a RowSpecification object representing the cell's row as the first argument and the cell's column index as the second. The datagrid must act as if the datagrid's updateCellChanged() method had been invoked with those same arguments immediately before the provider's method was invoked.

When a cell has a checkbox, the user must be able to set the checkbox's state. When the user changes the state of a checkbox in such a cell, the datagrid must invoke the data provider's setCellCheckedState() method, with a RowSpecification object representing the cell's row as the first argument, the cell's column index as the second, and the checkbox's new state as the third. The state should be represented by the number 1 if the new state is checked, 0 if the new state is unchecked, and −1 if the new state is indeterminate (which must be possible only if the cell has the indeterminate class set). The datagrid must act as if the datagrid's updateCellChanged() method had been invoked, specifying the same cell, immediately before the provider's method was invoked.

If a cell is editable, the user must be able to edit the data for that cell, and doing so must cause the user agent to invoke the editCell() method of the data provider with three arguments: a RowSpecification object representing the cell's row, the cell's column's index, and the new text entered by the user. The user agent must act as if the updateCellChanged() method had been invoked, with the same row and column specified, immediately before the provider's method was invoked.

4.11.2.8. The selection

This section only applies to interactive user agents. For other user agents, the selection attribute must return null.

interface DataGridSelection {
  readonly attribute unsigned long length;
  [IndexGetter] RowSpecification item(in unsigned long index);
  boolean isSelected(in RowSpecification row);
  void setSelected(in RowSpecification row, in boolean selected);

  void selectAll();
  void invert();
  void clear();
};

Each datagrid element must keep track of which rows are currently selected. Initially no rows are selected, but this can be changed via the methods described in this section.

The selection of a datagrid is represented by its selection DOM attribute, which must be a DataGridSelection object.

DataGridSelection objects represent the rows in the selection. In the selection the rows must be ordered in the natural order of the data provider (and not, e.g., the rendered order). Rows that are not rendered because one of their ancestors is closed must share the same selection state as their nearest rendered ancestor. Such rows are not considered part of the selection for the purposes of iterating over the selection.

This selection API doesn't allow for hidden rows to be selected because it is trivial to create a data provider that has infinite depth, which would then require the selection to be infinite if every row, including every hidden row, was selected.

The length attribute must return the number of rows currently present in the selection. The item(index) method must return the indexth row in the selection. If the argument is out of range (less than zero or greater than the number of selected rows minus one), then it must raise an INDEX_SIZE_ERR exception. [DOM3CORE]

The isSelected() method must return the selected state of the row specified by its argument. If the specified row exists and is selected, it must return true, otherwise it must return false.

The setSelected() method takes two arguments, row and selected. When invoked, it must set the selection state of row row to selected if selected is true, and unselected if it is false. If row is not a row in the data grid, the method must raise an INDEX_SIZE_ERR exception. If the specified row is not rendered because one of its ancestors is closed, the method must do nothing.

The selectAll() method must mark all the rows in the data grid as selected. After a call to selectAll(), the length attribute will return the number of rows in the data grid, not counting children of closed rows.

The invert() method must cause all the rows in the selection that were marked as selected to now be marked as not selected, and vice versa.

The clear() method must mark all the rows in the data grid to be marked as not selected. After a call to clear(), the length attribute will return zero.

If the datagrid element has a multiple attribute, then the user must be able to select any number of rows (zero or more). If the attribute is not present, then the user must not be able to select more than a single row at a time, and selecting another one must unselect all the other rows.

This only applies to the user. Scripts can select multiple rows even when the multiple attribute is absent.

Whenever the selection of a datagrid changes, whether due to the user interacting with the element, or as a result of calls to methods of the selection object, a select event that bubbles but is not cancelable must be fired on the datagrid element. If changes are made to the selection via calls to the object's methods during the execution of a script, then the select events must be coalesced into one, which must then be fired when the script execution has completed.

The DataGridSelection interface has no relation to the Selection interface.

4.11.2.9. Columns and captions

This section only applies to interactive user agents.

Each datagrid element must keep track of which columns are currently being rendered. User agents should initially show all the columns except those with the initially-hidden class, but may allow users to hide or show columns. User agents should initially display the columns in the order given by the data provider, but may allow this order to be changed by the user.

If columns are not being used, as might be the case if the data grid is being presented in an icon view, or if an overview of data is being read in an aural context, then the text of the first column of each row should be used to represent the row.

If none of the columns have any captions (i.e. if the data provider does not provide a getCaptionText() method), then user agents may avoid showing the column headers at all. This may prevent the user from performing actions on the columns (such as reordering them, changing the sort column, and so on).

Whatever the order used for rendering, and irrespective of what columns are being shown or hidden, the "first column" as referred to in this specification is always the column with index zero, and the "last column" is always the column with the index one less than the value returned by the getColumnCount() method of the data provider.

If a column is sortable, then the user must be able to invoke it to sort the data. When the user does so, then the datagrid must invoke the data provider's toggleColumnSortState() method, with the column's index as the only argument. The datagrid must then act as if the datagrid's updateEverything() method had been invoked.

4.11.3 The command element

Categories
Metadata content.
Phrasing content.
Contexts in which this element may be used:
Where metadata content is expected.
Where phrasing content is expected.
Content model:
Empty.
Element-specific attributes:
type
label
icon
hidden
disabled
checked
radiogroup
default
Also, the title attribute has special semantics on this element.
DOM interface:
interface HTMLCommandElement : HTMLElement {
           attribute DOMString type;
           attribute DOMString label;
           attribute DOMString icon;
           attribute boolean hidden;
           attribute boolean disabled;
           attribute boolean checked;
           attribute DOMString radiogroup;
           attribute boolean default;
 void click(); // shadows HTMLElement.click()
};

The Command interface must also be implemented by this element.

The command element represents a command that the user can invoke.

The type attribute indicates the kind of command: either a normal command with an associated action, or a state or option that can be toggled, or a selection of one item from a list of items.

The attribute's value must be either "command", "checkbox", or "radio", denoting each of these three types of commands respectively. The attribute may also be omitted if the element is to represent the first of these types, a simple command.

The label attribute gives the name of the command, as shown to the user.

The title attribute gives a hint describing the command, which might be shown to the user to help him.

The icon attribute gives a picture that represents the command. If the attribute is specified, the attribute's value must contain a valid URL.

The hidden attribute is a boolean attribute that, if present, indicates that the command is not relevant and is to be hidden.

The disabled attribute is a boolean attribute that, if present, indicates that the command is not available in the current state.

The distinction between Disabled State and Hidden State is subtle. A command should be Disabled if, in the same context, it could be enabled if only certain aspects of the situation were changed. A command should be marked as Hidden if, in that situation, the command will never be enabled. For example, in the context menu for a water faucet, the command "open" might be Disabled if the faucet is already open, but the command "eat" would be marked Hidden since the faucet could never be eaten.

The checked attribute is a boolean attribute that, if present, indicates that the command is selected.

The radiogroup attribute gives the name of the group of commands that will be toggled when the command itself is toggled, for commands whose type attribute has the value "radio". The scope of the name is the child list of the parent element.

If the command element is used when generating a context menu, then the default attribute indicates, if present, that the command is the one that would have been invoked if the user had directly activated the menu's subject instead of using its context menu. The default attribute is a boolean attribute.

Need an example that shows an element that, if double-clicked, invokes an action, but that also has a context menu, showing the various command attributes off, and that has a default command.

The type, label, icon, hidden, disabled, checked, radiogroup, and default DOM attributes must reflect their respective namesake content attributes.

The click() method's behavior depends on the value of the type attribute of the element, as follows:

If the type attribute has the value checkbox

If the element has a checked attribute, the UA must remove that attribute. Otherwise, the UA must add a checked attribute, with the literal value checked. The UA must then fire a click event at the element.

If the type attribute has the value radio

If the element has a parent, then the UA must walk the list of child nodes of that parent element, and for each node that is a command element, if that element has a radiogroup attribute whose value exactly matches the current element's (treating missing radiogroup attributes as if they were the empty string), and has a checked attribute, must remove that attribute and fire a click event at the element.

Then, the element's checked attribute attribute must be set to the literal value checked and a click event must be fired at the element.

Otherwise

The UA must fire a click event at the element.

Firing a synthetic click event at the element does not cause any of the actions described above to happen.

should change all the above so it actually is just triggered by a click event, then we could remove the shadowing click() method and rely on actual events.

Need to define the command="" attribute

command elements are not rendered unless they form part of a menu.

Categories
Flow content.
If there is a menu element ancestor: phrasing content.
Contexts in which this element may be used:
Where flow content is expected.
If there is a menu element ancestor: where phrasing content is expected.
Content model:
Either: Zero or more li elements.
Or: Phrasing content.
Element-specific attributes:
type
label
autosubmit
DOM interface:
interface HTMLMenuElement : HTMLElement {
           attribute DOMString type;
           attribute DOMString label;
           attribute boolean autosubmit;
};

The menu element represents a list of commands.

The type attribute is an enumerated attribute indicating the kind of menu being declared. The attribute has three states. The context keyword maps to the context menu state, in which the element is declaring a context menu. The toolbar keyword maps to the tool bar state, in which the element is declaring a tool bar. The attribute may also be omitted. The missing value default is the list state, which indicates that the element is merely a list of commands that is neither declaring a context menu nor defining a tool bar.

If a menu element's type attribute is in the context menu state, then the element represents the commands of a context menu, and the user can only interact with the commands if that context menu is activated.

If a menu element's type attribute is in the tool bar state, then the element represents a list of active commands that the user can immediately interact with.

If a menu element's type attribute is in the list state, then the element either represents an unordered list of items (each represented by an li element), each of which represents a command that the user may perform or activate, or, if the element has no li element children, flow content describing available commands.

The label attribute gives the label of the menu. It is used by user agents to display nested menus in the UI. For example, a context menu containing another menu would use the nested menu's label attribute for the submenu's menu label.

The autosubmit attribute is a boolean attribute that, if present, indicates that selections made to form controls in this menu are to result in the control's form being immediately submitted.

If a change event bubbles through a menu element, then, in addition to any other default action that that event might have, the UA must act as if the following was an additional default action for that event: if (when it comes time to execute the default action) the menu element has an autosubmit attribute, and the target of the event is an input element, and that element has a type attribute whose value is either radio or checkbox, and the input element in question has a non-null form DOM attribute, then the UA must invoke the submit() method of the form element indicated by that DOM attribute.

This section is non-normative.

...

4.11.4.2. Building menus and tool bars

A menu (or tool bar) consists of a list of zero or more of the following components:

The list corresponding to a particular menu element is built by iterating over its child nodes. For each child node in tree order, the required behavior depends on what the node is, as follows:

An element that defines a command
Append the command to the menu. If the element is a command element with a default attribute, mark the command as being a default command.
An hr element
An option element that has a value attribute set to the empty string, and has a disabled attribute, and whose textContent consists of a string of one or more hyphens (U+002D HYPHEN-MINUS)
Append a separator to the menu.
An li element
Iterate over the children of the li element.
A menu element with no label attribute
A select element
Append a separator to the menu, then iterate over the children of the menu or select element, then append another separator.
A menu element with a label attribute
An optgroup element
Append a submenu to the menu, using the value of the element's label attribute as the label of the menu. The submenu must be constructed by taking the element and creating a new menu for it using the complete process described in this section.
Any other node
Ignore the node.

We should support label in the algorithm above -- just iterate through the contents like with li, to support input elements in label elements. Also, optgroup elements without labels should be ignored (maybe? or at least should say they have no label so that they are dropped below), and select elements inside label elements may need special processing.

Once all the nodes have been processed as described above, the user agent must the post-process the menu as follows:

  1. Any menu item with no label, or whose label is the empty string, must be removed.
  2. Any sequence of two or more separators in a row must be collapsed to a single separator.
  3. Any separator at the start or end of the menu must be removed.
4.11.4.3. Context menus

The contextmenu attribute gives the element's context menu. The value must be the ID of a menu element in the DOM. If the node that would be obtained by the invoking the getElementById() method using the attribute's value as the only argument is null or not a menu element, then the element has no assigned context menu. Otherwise, the element's assigned context menu is the element so identified.

When an element's context menu is requested (e.g. by the user right-clicking the element, or pressing a context menu key), the UA must fire a contextmenu event on the element for which the menu was requested.

Typically, therefore, the firing of the contextmenu event will be the default action of a mouseup or keyup event. The exact sequence of events is UA-dependent, as it will vary based on platform conventions.

The default action of the contextmenu event depends on whether the element has a context menu assigned (using the contextmenu attribute) or not. If it does not, the default action must be for the user agent to show its default context menu, if it has one.

Context menus should inherit (so clicking on a span in a paragraph with a context menu should show the menu).

If the element does have a context menu assigned, then the user agent must fire a show event on the relevant menu element.

The default action of this event is that the user agent must show a context menu built from the menu element.

The user agent may also provide access to its default context menu, if any, with the context menu shown. For example, it could merge the menu items from the two menus together, or provide the page's context menu as a submenu of the default menu.

If the user dismisses the menu without making a selection, nothing in particular happens.

If the user selects a menu item that represents a command, then the UA must invoke that command's Action.

Context menus must not, while being shown, reflect changes in the DOM; they are constructed as the default action of the show event and must remain like that until dismissed.

User agents may provide means for bypassing the context menu processing model, ensuring that the user can always access the UA's default context menus. For example, the user agent could handle right-clicks that have the Shift key depressed in such a way that it does not fire the contextmenu event and instead always shows the default context menu.

The contextMenu attribute must reflect the contextmenu content attribute.

4.11.4.4. Toolbars

Toolbars are a kind of menu that is always visible.

When a menu element has a type attribute with the value toolbar, then the user agent must build the menu for that menu element and render it in the document in a position appropriate for that menu element.

The user agent must reflect changes made to the menu's DOM immediately in the UI.

4.11.5 Commands

A command is the abstraction behind menu items, buttons, and links. Once a command is defined, other parts of the interface can refer to the same command, allowing many access points to a single feature to share aspects such as the disabled state.

Commands are defined to have the following facets:

Type
The kind of command: "command", meaning it is a normal command; "radio", meaning that triggering the command will, amongst other things, set the Checked State to true (and probably uncheck some other commands); or "checkbox", meaning that triggering the command will, amongst other things, toggle the value of the Checked State.
ID
The name of the command, for referring to the command from the markup or from script. If a command has no ID, it is an anonymous command.
Label
The name of the command as seen by the user.
Hint
A helpful or descriptive string that can be shown to the user.
Icon
An absolute URL identifying a graphical image that represents the action. A command might not have an Icon.
Hidden State
Whether the command is hidden or not (basically, whether it should be shown in menus).
Disabled State
Whether the command can be triggered or not. If the Hidden State is true (hidden) then the Disabled State will be true (disabled) regardless. We could make this into a string value that acts as a Hint for why the command is disabled.
Checked State
Whether the command is checked or not.
Action
The actual effect that triggering the command will have. This could be a scripted event handler, a URL to which to navigate, or a form submission.
Triggers
The list of elements that can trigger the command. The element defining a command is always in the list of elements that can trigger the command. For anonymous commands, only the element defining the command is on the list, since other elements have no way to refer to it.

Commands are represented by elements in the DOM. Any element that can define a command also implements the Command interface:

Actually even better would be to just mix it straight into those interfaces somehow.

[NoInterfaceObject] interface Command {
  readonly attribute DOMString commandType;          
  readonly attribute DOMString id;
  readonly attribute DOMString label;
  readonly attribute DOMString title;
  readonly attribute DOMString icon;
  readonly attribute boolean hidden;
  readonly attribute boolean disabled;              
  readonly attribute boolean checked;              
  void click();
  readonly attribute HTMLCollection triggers;
  readonly attribute Command command;
};

The Command interface is implemented by any element capable of defining a command. (If an element can define a command, its definition will list this interface explicitly.) All the attributes of the Command interface are read-only. Elements implementing this interface may implement other interfaces that have attributes with identical names but that are mutable; in bindings that flatten all supported interfaces on the object, the mutable attributes must shadow the readonly attributes defined in the Command interface.

The commandType attribute must return a string whose value is either "command", "radio", or "checked", depending on whether the Type of the command defined by the element is "command", "radio", or "checked" respectively. If the element does not define a command, it must return null.

The id attribute must return the command's ID, or null if the element does not define a command or defines an anonymous command. This attribute will be shadowed by the id DOM attribute on the HTMLElement interface.

The label attribute must return the command's Label, or null if the element does not define a command or does not specify a Label. This attribute will be shadowed by the label DOM attribute on option and command elements.

The title attribute must return the command's Hint, or null if the element does not define a command or does not specify a Hint. This attribute will be shadowed by the title DOM attribute on the HTMLElement interface.

The icon attribute must return the absolute URL of the command's Icon. If the element does not specify an icon, or if the element does not define a command, then the attribute must return null. This attribute will be shadowed by the icon DOM attribute on command elements.

The hidden attribute must return true if the command's Hidden State is that the command is hidden, and false if it is that the command is not hidden. If the element does not define a command, the attribute must return false. This attribute will be shadowed by the hidden DOM attribute on command elements.

The disabled attribute must return true if the command's Disabled State is that the command is disabled, and false if the command is not disabled. This attribute is not affected by the command's Hidden State. If the element does not define a command, the attribute must return false. This attribute will be shadowed by the disabled attribute on button, input, option, and command elements.

The checked attribute must return true if the command's Checked State is that the command is checked, and false if it is that the command is not checked. If the element does not define a command, the attribute must return false. This attribute will be shadowed by the checked attribute on input and command elements.

The click() method must trigger the Action for the command. If the element does not define a command, this method must do nothing. This method will be shadowed by the click() method on HTML elements, and is included only for completeness.

The triggers attribute must return a list containing the elements that can trigger the command (the command's Triggers). The list must be live. While the element does not define a command, the list must be empty.

The commands attribute of the document's HTMLDocument interface must return an HTMLCollection rooted at the Document node, whose filter matches only elements that define commands and have IDs.

The following elements can define commands: a, button, input, option, command.

4.11.5.1. Using the a element to define a command

An a element with an href attribute defines a command.

The Type of the command is "command".

The ID of the command is the value of the id attribute of the element, if the attribute is present and not empty. Otherwise the command is an anonymous command.

The Label of the command is the string given by the element's textContent DOM attribute.

The Hint of the command is the value of the title attribute of the element. If the attribute is not present, the Hint is the empty string.

The Icon of the command is the absolute URL obtained from resolving the value of the src attribute of the first img element descendant of the element, if there is such an element and resolving its attribute is successful. Otherwise, there is no Icon for the command.

The Hidden State and Disabled State facets of the command are always false. (The command is always enabled.)

The Checked State of the command is always false. (The command is never checked.)

The Action of the command is to fire a click event at the element.

4.11.5.2. Using the button element to define a command

A button element always defines a command.

The Type, ID, Label, Hint, Icon, Hidden State, Checked State, and Action facets of the command are determined as for a elements (see the previous section).

The Disabled State of the command mirrors the disabled state of the button. Typically this is given by the element's disabled attribute, but certain button types become disabled at other times too (for example, the move-up button type is disabled when it would have no effect).

4.11.5.3. Using the input element to define a command

An input element whose type attribute is one of submit, reset, button, radio, checkbox, move-up, move-down, add, and remove defines a command.

The Type of the command is "radio" if the type attribute has the value radio, "checkbox" if the type attribute has the value checkbox, and "command" otherwise.

The ID of the command is the value of the id attribute of the element, if the attribute is present and not empty. Otherwise the command is an anonymous command.

The Label of the command depends on the Type of the command:

If the Type is "command", then it is the string given by the value attribute, if any, and a UA-dependent value that the UA uses to label the button itself if the attribute is absent.

Otherwise, the Type is "radio" or "checkbox". If the element has a label element associated with it, the textContent of the first such element is the Label (in DOM terms, this the string given by element.labels[0].textContent). Otherwise, the value of the value attribute, if present, is the Label. Otherwise, the Label is the empty string.

The Hint of the command is the value of the title attribute of the input element. If the attribute is not present, the Hint is the empty string.

There is no Icon for the command.

The Hidden State of the command is always false. (The command is never hidden.)

The Disabled State of the command mirrors the disabled state of the control. Typically this is given by the element's disabled attribute, but certain input types become disabled at other times too (for example, the move-up input type is disabled when it would have no effect).

The Checked State of the command is true if the command is of Type "radio" or "checkbox" and the element has a checked attribute, and false otherwise.

The Action of the command is to fire a click event at the element.

4.11.5.4. Using the option element to define a command

An option element with an ancestor select element and either no value attribute or a value attribute that is not the empty string defines a command.

The Type of the command is "radio" if the option's nearest ancestor select element has no multiple attribute, and "checkbox" if it does.

The ID of the command is the value of the id attribute of the element, if the attribute is present and not empty. Otherwise the command is an anonymous command.

The Label of the command is the value of the option element's label attribute, if there is one, or the value of the option element's textContent DOM attribute if it doesn't.

The Hint of the command is the string given by the element's title attribute, if any, and the empty string if the attribute is absent.

There is no Icon for the command.

The Hidden State of the command is always false. (The command is never hidden.)

The Disabled State of the command is true (disabled) if the element has a disabled attribute, and false otherwise.

The Checked State of the command is true (checked) if the element's selected DOM attribute is true, and false otherwise.

The Action of the command depends on its Type. If the command is of Type "radio" then this must set the selected DOM attribute of the option element to true, otherwise it must toggle the state of the selected DOM attribute (set it to true if it is false and vice versa). Then a change event must be fired on the option element's nearest ancestor select element (if there is one), as if the selection had been changed directly.

4.11.5.5. Using the command element to define a command

A command element defines a command.

The Type of the command is "radio" if the command's type attribute is "radio", "checkbox" if the attribute's value is "checkbox", and "command" otherwise.

The ID of the command is the value of the id attribute of the element, if the attribute is present and not empty. Otherwise the command is an anonymous command.

The Label of the command is the value of the element's label attribute, if there is one, or the empty string if it doesn't.

The Hint of the command is the string given by the element's title attribute, if any, and the empty string if the attribute is absent.

The Icon for the command is the absolute URL obtained from resolving the value of the element's icon attribute, if it has such an attribute and resolving it is successful. Otherwise, there is no Icon for the command.

The Hidden State of the command is true (hidden) if the element has a hidden attribute, and false otherwise.

The Disabled State of the command is true (disabled) if the element has either a disabled attribute or a hidden attribute (or both), and false otherwise.

The Checked State of the command is true (checked) if the element has a checked attribute, and false otherwise.

The Action of the command is to invoke the behavior described in the definition of the click() method of the HTMLCommandElement interface.

4.12 Data Templates

4.12.1 Introduction

This section is non-normative.

...examples...

4.12.2 The datatemplate element

Categories
Metadata content.
Flow content.
Contexts in which this element may be used:
As the root element of an XML document.
Where metadata content is expected.
Where flow content is expected.
Content model:
Zero or more rule elements.
Element-specific attributes:
None.
DOM interface:
Uses HTMLElement.

The datatemplate element brings together the various rules that form a data template. The element doesn't itself do anything exciting.

4.12.3 The rule element

Categories
None.
Contexts in which this element may be used:
As a child of a datatemplate element.
Content model:
Anything, regardless of the children's required contexts (but see prose).
Element-specific attributes:
condition
mode
DOM interface:
interface HTMLRuleElement : HTMLElement {
           attribute DOMString condition;
           attribute DOMString mode;
  readonly attribute DOMTokenString modeList;
};

The rule element represents a template of content that is to be used for elements when updating an element's generated content.

The condition attribute, if specified, must contain a valid selector. It specifies which nodes in the data tree will have the condition's template applied. [SELECTORS]

If the condition attribute is not specified, then the condition applies to all elements, text nodes, CDATA nodes, and processing instructions.

The mode attribute, if specified, must have a value that is an unordered set of unique space-separated tokens representing the various modes for which the rule applies. When, and only when, the mode attribute is omitted, the rule applies if and only if the mode is the empty string. A mode is invoked by the nest element; for the first node (the root node) of the data tree, the mode is the empty string.

The contents of rule elements form a template, and may be anything that, when the parent datatemplate is applied to some conforming data, results in a conforming DOM tree.

The condition DOM attribute must reflect the condition content attribute.

The mode and modeList DOM attributes must reflect the mode content attribute.

4.12.4 The nest element

Categories
None.
Contexts in which this element may be used:
As a child of a descendant of a rule element, regardless of the element's content model.
Content model:
Empty.
Element-specific attributes:
filter
mode
DOM interface:
interface HTMLNestElement : HTMLElement {
           attribute DOMString filter;
           attribute DOMString mode;
};

The nest element represents a point in a template where the user agent should recurse and start inserting the children of the data node that matches the rule in which the nest element finds itself.

The filter attribute, if specified, must contain a valid selector. It specifies which of the child nodes in the data tree will be examined for further processing at this point. [SELECTORS]

If the filter attribute is not specified, then all elements, text nodes, CDATA nodes, and processing instructions are processed.

The mode attribute, if specified, must have a value that is a word token consisting of one or more characters, none of which are space characters. It gives the mode which will be in effect when looking at the rules in the data template.

The filter DOM attribute must reflect the filter content attribute.

The mode DOM attribute must reflect the mode content attribute.

4.12.5 Global attributes for data templates

The template attribute may be added to an element to indicate that the template processing model is to be applied to that element.

The template attribute, when specified, must be a valid URL to an XML or HTML document, or a fragment identifier pointing at another part of the document. If there is a fragment identifier present, then the element with that ID in the target document must be a datatemplate element, otherwise, the root element must be a datatemplate element.

The template DOM attribute must reflect the template content attribute.

The ref attribute may be specified on any element on which the template attribute is specified. If it is specified, it must be a valid URL to an XML or HTML document, or a fragment identifier pointing at another part of the document.

When an element has a template attribute but no ref attribute, the element may, instead of its usual content model, have a single element of any kind. That element is then used as the root node of the data for the template.

The ref DOM attribute must reflect the ref content attribute.

The registrationmark attribute may be specified on any element that is a descendant of a rule element, except nest elements. Its value may be any string, including the empty string (which is the value that is assumed if the attribute is omitted). This attribute performs a role similar to registration marks in printing presses: when the generated content is regenerated, elements with the same registrationmark are lined up. This allows the author to disambiguate how elements should be moved around when generated content is regenerated in the face of changes to the data tree.

The registrationMark DOM attribute must reflect the registrationmark content attribute.

4.12.6 Processing model

4.12.6.1. The originalContent DOM attribute

The originalContent is set to a DocumentFragment to hold the original children of an element that has been replaced by content generated for a data template. Initially, it must be null. Its value is set when the template attribute is set to a usable value, and is unset when the attribute is removed.

The originalContent DOM attribute can thus be used as an indicator of whether a template is currently being applied, just as the templateElement DOM attribute can.

4.12.6.2. The template attribute

Setting: When an HTML element without a template attribute has its template attribute set, the user agent must fetch the specified file and parse it (without a browsing context) to obtain a DOM. If the URL, when resolved, is the same as the document's address, then the current document's DOM must be assumed to be that parsed DOM. While this loading and parsing is in progress, the element is said to be busy loading the template rules or data.

If the resource specified by the template attribute is not the current document and does not have an XML MIME type, or if an XML parse error is found while parsing the resource, then the resource cannot be successfully parsed, and the user agent must jump to the failed to parse steps below.

Once the DOM in question has been parsed, assuming that it indeed can be parsed and does so successfully, the user agent must wait for no scripts to be executing, and as soon as that opportunity arises, run the following algorithm:

  1. If the template attribute's value has a fragment identifier, and, in the DOM in question, it identifies a datatemplate element, then set the templateElement DOM attribute to that element.

    Otherwise, if the template attribute value does not have a fragment identifier, and the root element of the DOM in question is a datatemplate element, then set the templateElement DOM attribute to that element.

    Otherwise, jump to the failed to parse steps below.

  2. Create a new DocumentFragment and move all the nodes that are children of the element to that DocumentFragment object. Set the originalContent DOM attribute on the element to this new DocumentFragment object.

  3. Jump to the steps below for updating the generated content.

If the resource has failed to parse, the user agent must fire a simple event with the name error at the element on which the template attribute was found.

Unsetting: When an HTML element with a template attribute has its template attribute removed or dynamically changed from one value to another, the user agent must run the following algorithm:

  1. Set the templateElement DOM attribute to null.

  2. If the originalContent DOM attribute of the element is not null, run these substeps:

    1. Remove all the nodes that are children of the element.

    2. Append the nodes in the originalContent DocumentFragment to the element.

    3. Set originalContent to null.

    (If the originalContent DOM attribute of the element is null, then either there was an error loading or parsing the previous template, or the previous template never finished loading; in either case, there is nothing to undo.)

  3. If the template attribute was changed (as opposed to simply removed), then act as if it was now set to its new value (fetching the specified page, etc, as described above).

The templateElement DOM attribute is updated by the above algorithm to point to the currently active datatemplate element. Initially, the attribute must have the value null.

4.12.6.3. The ref attribute

Setting: When an HTML element without a ref attribute has its ref attribute set, the user agent must fetch the specified file and parse it (without a browsing context) to obtain a DOM. If the URL, when resolved, is the same as the document's address, then the current document's DOM must be assumed to be that parsed DOM. While this loading and parsing is in progress, the element is said to be busy loading the template rules or data.

If the resource specified by the ref attribute is not the current document and does not have an XML MIME type, or if an XML parse error is found while parsing the resource, then the resource cannot be successfully parsed, and the user agent must jump to the failed to parse steps below.

Once the DOM in question has been parsed, assuming that it indeed can be parsed and does so successfully, the user agent must wait for no scripts to be executing, and as soon as that opportunity arises, run the following algorithm:

  1. If the ref attribute value does not have a fragment identifier, then set the refNode DOM attribute to the Document node of that DOM.

    Otherwise, if the ref attribute's value has a fragment identifier, and, in the DOM in question, that fragment identifier identifies an element, then set the refNode DOM attribute to that element.

    Otherwise, jump to the failed to parse steps below.

  2. Jump to the steps below for updating the generated content.

If the resource has failed to parse, the user agent must fire a simple event with the name error at the element on which the ref attribute was found, and must then jump to the steps below for updating the generated content (the contents of the element will be used instead of the specified resource).

Unsetting: When an HTML element with a ref attribute has its ref attribute removed or dynamically changed from one value to another, the user agent must run the following algorithm:

  1. Set the refNode DOM attribute to null.

  2. If the ref attribute was changed (as opposed to simply removed), then act as if it was now set to its new value (fetching the specified page, etc, as described above). Otherwise, jump to the steps below for updating the generated content.

The refNode DOM attribute is updated by the above algorithm to point to the current data tree, if one is specified explicitly. If it is null, then the data tree is given by the originalContent DOM attribute, unless that is also null, in which case no template is currently being applied. Initially, the attribute must have the value null.

4.12.6.4. The NodeDataTemplate interface

All objects that implement the Node interface must also implement the NodeDataTemplate interface, whose members must be accessible using binding-specific casting mechanisms.

interface NodeDataTemplate {
  readonly attribute Node dataNode;
};

The dataNode DOM attribute returns the node for which this node was generated. It must initially be null. It is set on the nodes that form the content generated during the algorithm for updating the generated content of elements that are using the data template feature.

4.12.6.5. Mutations

An element with a non-null templateElement is said to be a data tree user of the node identified by the element's refNode attribute, as well as all of that node's children, or, if that attribute is null, of the node identified by the element's originalContent, as well as all that node's children.

Nodes that have one or more data tree users associated with them (as per the previous paragraph) are themselves termed data tree component nodes.

Whenever a data tree component node changes its name or value, or has one of its attributes change name or value, or has an attribute added or removed, or has a child added or removed, the user agent must update the generated content of all of that node's data tree users.

An element with a non-null templateElement is also said to be a template tree user of the node identified by the element's templateElement attribute, as well as all of that node's children.

Nodes that have one or more template tree users associated with them (as per the previous paragraph) are themselves termed template tree component nodes.

Whenever a template tree component node changes its name or value, or has one of its attributes change name or value, or has an attribute added or removed, or has a child added or removed, the user agent must update the generated content of all of that node's template tree users.

In other words, user agents update the content generated from a template whenever either the backing data changes or the template itself changes.

4.12.6.6. Updating the generated content

When the user agent is to update the generated content of an element that uses a template, the user agent must run the following steps:

  1. Let destination be the element whose generated content is being updated.

  2. If the destination element is busy loading the template rules or data, then abort these steps. Either the steps will be invoked again once the loading has completed, or the loading will fail and the generated content will be removed at that point.

  3. Let template tree be the element given by destination's templateElement DOM attribute. If it is null, then abort these steps. There are no rules to apply.

  4. Let data tree be the node given by destination's refNode DOM attribute. If it is null, then let data tree be the node given by the originalContent DOM node.

  5. Let existing nodes be a set of ordered lists of nodes, each list being identified by a tuple consisting of a node, a node type and name, and a registration mark (a string).

  6. For each node node that is a descendant of destination, if any, add node to the list identified by the tuple given by: node's dataNode DOM attribute; the node's node type and, if it's an element, its qualified name (that is, its namespace and local name), or, if it's a processing instruction, its target name, and the value of the node's registrationmark attribute, if it has one, or the empty string otherwise.

  7. Remove all the child nodes of destination, so that its child node list is empty.

  8. Run the Levenberg data node algorithm (described below) using destination as the destination node, data tree as the source node, template tree as the rule container, the empty string as the mode, and the existing nodes lists as the lists of existing nodes.

The Levenberg algorithm consists of two algorithms that invoke each other recursively, the Levenberg data node algorithm and the Levenberg template node algorithm. These algorithms use the data structures initialized by the set of steps described above.

The Levenberg data node algorithm is as follows. It is always invoked with three DOM nodes, one string, and a set of lists as arguments: the destination node, the source node, the rule container, the mode string, and the existing nodes lists respectively.

  1. Let condition be the first rule element child of the rule container element, or null if there aren't any.

  2. If condition is null, follow these substeps:

    1. If the source node is an element, then, for each child child node of the source node element, in tree order, invoke the Levenberg data node algorithm recursively, with destination node, child node, rule container, the empty string, and existing nodes lists as the five arguments respectively.

    2. Abort the current instance of the Levenberg data node algorithm, returning to whatever algorithm invoked it.

  3. Let matches be a boolean with the value true.

  4. If the condition element has a mode attribute, but the value of that attribute is not a mode match for the current mode string, then let matches be false.

  5. If the condition element has a condition attribute, and the attribute's value, when evaluated as a selector, does not match the current source node, then let matches be false.

  6. If matches is true, then follow these substeps:

    1. For each child child node of the condition element, in tree order, invoke the Levenberg template node algorithm recursively, with the five arguments being destination node, source node, rule container, child node, and existing nodes lists respectively.

    2. Abort the current instance of the Levenberg data node algorithm, returning to whatever algorithm invoked it.

  7. Let condition be the next rule element that is a child of the rule container element, after the condition element itself, or null if there are no more rule elements.

  8. Jump to step 2 in this set of steps.

The Levenberg template node algorithm is as follows. It is always invoked with four DOM nodes and a set of lists as arguments: the destination node, the source node, the rule container, the template node, and the existing nodes lists respectively.

  1. If template node is a comment node, abort the current instance of the Levenberg template node algorithm, returning to whatever algorithm invoked it.

  2. If template node is a nest element, then run these substeps:

    1. If source node is not an element, then abort the current instance of the Levenberg template node algorithm, returning to whatever algorithm invoked it.

    2. If the template node has a mode attribute, then let mode be the value of that attribute; otherwise, let mode be the empty string.

    3. Let child node be the first child of the source node element, or null if source node has no children.

    4. If child node is null, abort the current instance of the Levenberg template node algorithm, returning to whatever algorithm invoked it.

    5. If the template node element has a filter attribute, and the attribute's value, when evaluated as a selector, matches child node, then invoke the Levenberg data node algorithm recursively, with destination node, child node, rule container, mode, and existing nodes lists as the five arguments respectively.

    6. Let child node be child node's next sibling, or null if child node was the last node of source node.

    7. Return to step 4 in this set of substeps.

  3. If template node is an element, and that element has a registrationmark attribute, then let registration mark have the value of that attribute. Otherwise, let registration mark be the empty string.

  4. If there is a list in the existing nodes lists corresponding to the tuple (source node, the node type and name of template node, registration mark), and that list is not empty, then run the following substeps. (For an element node, the name of the node is its qualified tag name, i.e. its namespace and local name. For a processing instruction, its name is the target. For other types of nodes, there is no name.)

    1. Let new node be the first node in that list.

    2. Remove new node from that list.

    3. If new node is an element, remove all the child nodes of new node, so that its child node list is empty.

    Otherwise, if there is no matching list, or there was, but it is now empty, then run these steps instead:

    1. Let new node be a shallow clone of template node.

    2. Let new node's dataNode DOM attribute be source node.

  5. If new node is an element, run these substeps:

    1. For each attribute on new node, if an attribute with the same qualified name is not present on template node, remove that attribute.

    2. For each attribute attribute on template node, run these substeps:

      1. Let expanded be the result of passing the value of attribute to the text expansion algorithm for templates along with source node.

      2. If an attribute with the same qualified name as attribute is already present on new node, then: if its value is different from expanded, replace its value with expanded.

      3. Otherwise, if there is no attribute with the same qualified name as attribute on new node, then add an attribute with the same namespace, prefix, and local name as attribute, with its value set to expanded's.

    Otherwise, the new node is a text node, CDATA block, or PI. Run these substeps instead:

    1. Let expanded be the result of passing the node value of template node (the content of the text node, CDATA block, or PI) to the text expansion algorithm for templates along with source node.

    2. If the value of the new node is different from expanded, then set the value of new node to expanded.

  6. Append new node to destination.

  7. If template node is an element, then, for each child child node of the template node element, in tree order, invoke the Levenberg template node algorithm recursively, with the five arguments being new child, source node, rule container, child node, and existing nodes lists respectively.

Define: evaluated as a selector

Define: text expansion algorithm for templates

4.13 Miscellaneous elements

4.13.1 The legend element

Categories
None.
Contexts in which this element may be used:
As the first child of a fieldset element.
As the first child of a details element.
As a child of a figure element, if there are no other legend element children of that element.
Content model:
Phrasing content.
Element-specific attributes:
None.
DOM interface:
Uses HTMLElement.

The legend element represents a title or explanatory caption for the rest of the contents of the legend element's parent element.

4.13.2 The div element

Categories
None.
Contexts in which this element may be used:
Where flow content is expected.
Content model:
Flow content.
Element-specific attributes:
None.
DOM interface:
Uses HTMLElement.

The div element represents nothing at all. It can be used with the class, lang/xml:lang, and title attributes to mark up semantics common to a group of consecutive elements.

Allowing div elements to contain phrasing content makes it easy for authors to abuse div, using it with the class="" attribute to the point of not having any other elements in the markup. This is a disaster from an accessibility point of view, and it would be nice if we could somehow make such pages non-compliant without preventing people from using divs as the extension mechanism that they are, to handle things the spec can't otherwise do (like making new widgets).