details elementInteractive, block-level element.
legend element followed by
either one or more block-level elements or inline-level content (but not both).
open
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?
datagrid elementInteractive, block-level element.
table element.
table element.
select element.
datalist element.
multiple
disabled
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.
datagrid data modelThis 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.
The chains of numbers that give a row's path, or identifier, are represented by objects that implement the RowSpecification interface.
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.
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
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)
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)
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)
getRowCount(parentRow).
getColumnCount()
datagrid's updateEverything() method must be
called.
getCaptionText(column)
datagrid's updateColumnChanged() method must
be called with the appropriate column index.
getCaptionClasses(column, classes)
datagrid's updateColumnChanged() method must
be called with the appropriate column index. Some classes have predefined meanings.
getRowImage(row)
datagrid's update methods must be called to
update the row in question.
getRowMenu(row)
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)
datagrid's update methods must be
called to update the row in question. Some classes have predefined meanings.
getCellData(row,
column)
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)
datagrid's update methods must be
called to update the rows or cells in question. Some classes have predefined meanings.
toggleColumnSortState(column)
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)
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)
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)
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.)
|
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 behaviour of the default data provider depends on the nature of the
first element child of the datagrid.
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:
sorted and reversed classes.
table element has a class attribute that
includes the sortable class, add the sortable class.
sorted class.
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): If the row's first cell's element
has an img element child, then the URI
of the row's image is the URI of the first img element child of the row's first cell's
element. Otherwise, the URI 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.
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:
optgroup element: header
class attribute contains
the closed class: initially-closed
class attribute contains
the open class: initially-open
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 initialised, 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.
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, h1-h6, 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 URI of the image given by 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.
In the following example, the row with path "1,0" returns "http://example.com/a" as its image URI, 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 decsendant
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:
class attribute contains the closed class: initially-closed
class attribute contains the open class: initially-open
h1-h6 element:
header
hr
element: separatorThe 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.
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.
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.
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.
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.
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.
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.
datagrid elementA 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:
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.
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.
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.
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.
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.
sorted
class applies to the column. If it does, then that column is the sorted
column, otherwise it is not.
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.
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).
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.
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.
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:
...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:
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 indentity transform; the data is rendered in its
natural order).
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.
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.
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 is entirely up to the UA.getRowImage() method with a RowSpecification object representing
the row in question. The return value is a string representing a URI (or
IRI) to an image. Relative URIs must be interpreted relative to the
datagrid's base URI. If the method
returns the empty string, null, or if the method is not defined, then the
row has no associated image.
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.
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.)
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.
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.
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.
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 appplies to the cell
and the cell's checkbox is in an indeterminate state. When the indeterminate class appplies 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 betwen 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 honour 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 behaviour 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.
datagridWhenever 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 indentified 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 only be called 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.
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" behaviour
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
only be possible 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.
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;
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 only be able
to select 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.
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.