AMPERSANDlt;/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.
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
attribute, if present, must be either empty or have the literal value multiple
. Similarly, the disabled
attribute, if present, must be either empty or have the literal value disabled
. (The actual values do not have any effect on how these attributes are processed, only the presence or absence of the attributes is important.)
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 objectinterface 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 DOMTokenString classes); DOMString getRowImage(in RowSpecification row); HTMLMenuElement getRowMenu(in RowSpecification row); void getRowClasses(in RowSpecification row, in DOMTokenString classes); DOMString getCellData(in RowSpecification row, in unsigned long column); void getCellClasses(in RowSpecification row, in unsigned long column, in DOMTokenString 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
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
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 select
element child of the datagrid
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:
AMPERSANDlt;datagrid> AMPERSANDlt;select> AMPERSANDlt;!-- the options and optgroups have had their labels and values removed to make the underlying structure clearer --> AMPERSANDlt;optgroup> AMPERSANDlt;option/> AMPERSANDlt;option/> AMPERSANDlt;/optgroup> AMPERSANDlt;optgroup> AMPERSANDlt;option/> AMPERSANDlt;optgroup id="a"> AMPERSANDlt;option/> AMPERSANDlt;option/> AMPERSANDlt;bogus/> AMPERSANDlt;option id="b"/> AMPERSANDlt;/optgroup> AMPERSANDlt;option/> AMPERSANDlt;/optgroup> AMPERSANDlt;/select>AMPERSANDlt;/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
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 option
element, 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:
AMPERSANDlt;datagrid> AMPERSANDlt;ol> AMPERSANDlt;li> row 0 AMPERSANDlt;/li> AMPERSANDlt;li> row 1 AMPERSANDlt;ol> AMPERSANDlt;li> row 1,0 AMPERSANDlt;/li> AMPERSANDlt;/ol> AMPERSANDlt;/li> AMPERSANDlt;li> row 2 AMPERSANDlt;/li> AMPERSANDlt;/ol>AMPERSANDlt;/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:
AMPERSANDlt;datagrid> AMPERSANDlt;ol> AMPERSANDlt;li> row 0 AMPERSANDlt;/li> AMPERSANDlt;li> row 1 AMPERSANDlt;ol> AMPERSANDlt;li> row 1,0 AMPERSANDlt;img src="http://example.com/a" alt=""> AMPERSANDlt;/li> AMPERSANDlt;/ol> AMPERSANDlt;/li> AMPERSANDlt;li> row 2 AMPERSANDlt;/li> AMPERSANDlt;/ol>AMPERSANDlt;/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: separator
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.
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
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 optgroup
s 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 AMPERSANDle; i AMPERSANDlt; 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 DOMTokenString
interface, initialised to empty. The index i must be in the range 0 AMPERSANDle; i AMPERSANDlt; N, where N is the total number of columns. The values contained in the DOMTokenString
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. The values contained in the DOMTokenString
object 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 DOMTokenString
interface, initialised to empty. The second argument must be a non-negative integer less than the total number of columns. The values contained in the DOMTokenString
object 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 0AMPERSANDnbsp;AMPERSANDle;AMPERSANDnbsp;piAMPERSANDnbsp;AMPERSANDlt;AMPERSANDnbsp;m-1 for all integer values of i in the range 0AMPERSANDnbsp;AMPERSANDle;AMPERSANDnbsp;iAMPERSANDnbsp;AMPERSANDlt;AMPERSANDnbsp;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 piAMPERSANDnbsp;=AMPERSANDnbsp;qi for all integer values of i in the range 0AMPERSANDnbsp;AMPERSANDle;AMPERSANDnbsp;iAMPERSANDnbsp;AMPERSANDlt;AMPERSANDnbsp;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.
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 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.
command
elementMetadata element, and strictly inline-level content.
head
element. type
label
icon
hidden
disabled
checked
radiogroup
default
title
attribute has special semantics on this element. 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(); // shadowsHTMLElement
.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 URI.
The hidden
attribute indicates, if present, that the command is not relevant and is to be hidden. If present, the attribute must have the exact value hidden
.
The disabled
attribute indicates, if present, that the command is not available in the current state. If present, the attribute must have the exact value disabled
.
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 indicates, if present, that the command is selected. If present, the attribute must have the exact value checked
.
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.
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 behaviour depends on the value of the type
attribute of the element, as follows:
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.
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.
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 trigged 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.
menu
elementBlock-level element, and structured inline-level element.
li
elements, or inline-level content (but not both). type
label
autosubmit
interface HTMLCommandElement : HTMLElement { attribute DOMString type; attribute DOMString label; attribute boolean autosubmit;};
The menu
element represents a list of commands.
The type
attribute indicates the kind of menu. It must have either the value popup
(to declare a context menu) or the value toolbar
(to define a tool bar). The attribute may also be omitted, to indicate 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 has a type
attribute with the value popup
, then it 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 has a type
attribute with the value toolbar
, then it represents a list of active commands that the user can immediately interact with.
Otherwise, if a menu
element has no type
attribute, or if has a type
attribute with a value other than popup
or toolbar
, then it 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, a paragraph 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 indicates whether selections made to form controls in this menu should result in the control's form being immediately submitted. If the attribute is present, its value must be autosubmit
.
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.
The processing model for menus is described in the next section.
legend
elementfieldset
element. details
element. figure
element, if there are no other legend
element children of that element. fieldset
or details
element: significant strictly inline-level content figure
element: inline-level content. HTMLElement
. The legend
element represents a title or explanatory caption for the rest of the contents of the legend
element's parent element.
div
elementerror
, example
, issue
, note
, search
, warning
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.
This section only applies to Web browsers.
Web browsers operate on browsing contexts, which have a session history.
Certain actions cause the browsing context to navigate to a new document. A new document could be an HTML or XML Document
, with a DOM, or it could be an image, or some other content. The new resource in question could have a URI, or it could be anonymous, for example a new document generated using the document.write()
API.
In addition, a particular resource can have multiple entries in the session history of a browsing context.
The requirements that the session history concept puts on user agents are defined in the session history and navigation section, which is structured around the APIs provided for scripts to interact with the session history.
This section discusses the various types of content that a user agent may find itself requested to dispay in a content area, and covers how those types of content should be handled.
This section will end up defining what the UA should do when the user clicks a link, types a link in the address bar, uses a bookmark, etc. This will probably involve being honest about the fact that UAs typically content sniff for RSS/Atom feeds at this point. It should also reference the registerProtocolHandler
and registerContentHandler
methods and their stuff. Also involves the session history and bfcache (there's a separate section on that though).
Must define the interaction of this with document.write() pages and navigating to javascript: URIs.
Must define that the global scope is cleared/put back when navigating, so that Window objects from other windows looking at this one see the attributes change when the page navigates; this does/doesn't affect .watch(); make sure the .back()/.forward() definitions refer to this section.
...
When an HTML page (as opposed to an XML page) is loaded in a browsing context, the user agent must begin to parse the stream of bytes as described in the parsing section.
create a Document
node, mark it as being an HTML document, create an HTML parser, associate them together, run the parser while pushing bytes into the end of the input stream, push an explicit EOF when you have no more bytes, and require the parser to wait for an explicit EOF in this case (or some equivalent)
This will usually eventually cause a load
event to be fired.
This needs to say that a parser is created, etc.
Must make sure we don't step on the toes of other specifications.
Must make sure we don't step on the toes of other specifications. This section should be referred to by the document.open() stuff.
...
This is a placeholder section for some text that will define exactly how to handle Content-Type headers for top-level browsing contexts, for AMPERSANDlt;img>, AMPERSANDlt;embed>, AMPERSANDlt;object>, etc; and will cover things like the fact that on some operating systems the extension of a URI determines the Content-Type for file:// content, or something.
Here are some of the things I think we should list:
Various mechanisms can cause author-provided executable code to run in the context of a document. These mechanisms include, but are probably not limited to:
script
elements. javascript:
URIs (e.g. the src
attribute of img
elements, or an @import
rule in a CSS style
element block). addEventListener()
, by explicit event handler content attributes, by event handler DOM attributes, or otherwise. User agents may provide a mechanism to enable or disable the execution of author-provided code. When the user agent is configured such that author-provided code does not execute, or if the user agent is implemented so as to never execute author-provided code, it is said that scripting is disabled. When author-provided code does execute, scripting is enabled. A user agent with scripting disabled is a user agent with no scripting support for the purposes of conformance.
Each Document
in a browsing context has an associated scripting context.
Each scripting context is defined as having a list of zero or more reachable scripting contexts. These are:
Document
s in each nested browsing context inside the scripting context's Document
. Document
that contains the Document
's browsing context. Document
s associated with any top-level browsing contexts that were opened from a Document
associated with the scripting context's Document
's browsing context. Document
s associated with the top-level browsing contexts of the browsing context of the WindowHTML
object returned by the scripting context's Document
's WindowHTML
's opener
attribute. The transitive closure of all the scripting contexts that are reachable scripting contexts consists of a unit of related scripting contexts.
All the executable code in a unit of related scripting contexts must execute on a single conceptual thread. While a script is executing, no other scripts in that unit of related scripting contexts must be started.
Events fired by the user agent in response to user actions must be queued, as must the execution of any timers. There must be only one queue per unit of related scripting contexts. When no script in the unit of related scripting contexts is executing, the oldest entry in the queue must be processed, either by firing the appropriate event, or by executing the relevant timer callback code.
Web browser vendors should implement this security model, to provide Web authors with a consistent development environment that is interoperable across different implementations. However, implementors may use any other model if desired.
The security model for Web browsers has grown organically with the development of the Web, and as such is somewhat unique.
Access to resources and APIs is granted or denied to Web content (scripts, elements, etc) based on the content's origin. For historical reasons, the mechanism for determining the origin of a particular piece of content depends on the nature of the content.
...
The domain of a Document
object is the domain given by the hostname
attribute of the Location
object returned by the Document
object's location
attribute, if that hostname
attribute is not the empty string. If it is, the domain of the document is UA-defined. For now. Need to be more correct about where .location is defined. It's not actually on Document.
The domain of a script is the domain of the Document
object that is returned by the document
attribute of the script's primary Window
object (in UAs that implement ECMAScript, that is the global scope object).
The string representing the script's domain in IDNA format is obtained as follows: take the script's domain and apply the IDNA ToASCII algorithm and then the IDNA ToUnicode algorithm to each component of the domain name (with both the AllowUnassigned and UseSTD3ASCIIRules flags set both times). [RFC3490] If ToASCII fails to convert one of the components of the string, e.g. because it is too long or because it contains invalid characters, then the string representing the script's domain in IDNA format cannot be obtained. (ToUnicode is defined to never fail.)
This section is so not complete.
Define security exception.
javascript:
URIsWhat's the scripting context for javascript: URIs in AMPERSANDlt;img src>, AMPERSANDlt;iframe src>, AMPERSANDlt;location.href>, AMPERSANDlt;a href>, @import, background-image, etc?
Whenever a runtime script error occurs in one of the scripts associated with the document, the value of the onerror
attribute of the window
object (defined on the WindowHTML
interface of that object), must be processed, as follows:
The function referenced by the onerror
attribute must be invoked with three arguments, before notifying the user of the error.
The three arguments passed to the function are all DOMString
s; the first must give the message that the UA is considering reporting, the second must give the URI to the resource in which the error occured, and the third must give the line number in that resource on which the error occured.
If the function returns false, then the error should not be reported to the user. Otherwise, if the function returns another value (or does not return at all), the error should be reported to the user.
Any exceptions thrown or errors caused by this function must be reported to the user immediately after the error that the function was called for, without calling the function again.
null
The error should not reported to the user.
The error should be reported to the user.
The initial value of onerror
must be undefined
.
HTML elements can have event handler attributes specified. These act as bubbling event listeners for the element on which they are specified.
Each event handler attribute has two parts, an event handler content attribute and an event handler DOM attribute. Event handler attributes must initially be set to null. When their value changes (through the changing of their event handler content attribute or their event handler DOM attribute), they will either be null, or have an EventListener
object assigned to them.
In the ECMAScript DOM binding, the ECMAScript native Function
type must implement the EventListener
interface such that invoking the handleEvent()
method of that interface on the object from another language binding invokes the function itself, with the event
argument as its only argument. In the ECMAScript binding itself, however, the handleEvent()
method of the interface is not directly accessible on Function
objects. Such functions, when invoked, must be called in the global scope. If the function returns false, the event's preventDefault()
method must then invoked. Exception: for historical reasons, for the HTML mouseover
event, the preventDefault()
method must be called when the function returns true instead.
Event handler content attributes, when specified, must contain valid ECMAScript code matching the ECMAScript FunctionBody
production. [ECMA262]
How do we allow non-JS event handlers?
When an event handler content attribute is set, its new value must be interpreted as the body of an anonymous function with a single argument called event
, with the new function's scope chain being linked from the activation object of the handler, to the element, to the element's form
element if it is a form control, to the Document
object, to the global scope. The function's this
parameter must be the Element
object representing the element. The resulting function must then be set as the value of the corresponding event handler attribute, and the new value must be set as the value of the content attribute. If the given function body fails to compile, then the corresponding event handler attribute must be set to null instead (the content attribute must still be updated to the new value, though).
See ECMA262 Edition 3, sections 10.1.6 and 10.2.3, for more details on activation objects. [ECMA262]
Event handler DOM attributes, on setting, must set the corresponding event handler attribute to their new value, and on getting, must return whatever the current value of the corresponding event handler attribute is (possibly null).
The following are the event handler attributes that must be supported by all HTML elements, as both content attributes and DOM attributes:
onclick
click
event is targetted at or bubbles through the element. maybe _this_ should be moved higher up (terminology? conformance? DOM?)
Certain operations and methods are defined as firing events on elements. For example, the click()
method on the HTMLElement
interface is defined as firing a click
event on the element. [DOM3EVENTS]
Firing a click
event means that a click
event in the http://www.w3.org/2001/xml-events
namespace, which bubbles and is cancelable, and which uses the MouseEvent
interface, must be dispatched at the given element. The event object must have its screenX
, screenY
, clientX
, clientY
, and button
attributes set to 0, its ctrlKey
, shiftKey
, altKey
, and metaKey
attributes set according to the current state of the key input device, if any (false for any keys that are not available), its detail
attribute set to 1, and its relatedTarget
attribute set to null. The getModifierState()
method on the object must return values appropriately describing the state of the key input device at the time the event is created.
Firing a change
event means that a change
event in the http://www.w3.org/2001/xml-events
namespace, which bubbles but is not cancelable, and which uses the Event
interface, must be dispatched at the given element. The event object must have its detail
attribute set to 0.
Firing a contextmenu
event means that a contextmenu
event in the http://www.w3.org/2001/xml-events
namespace, which bubbles and is cancelable, and which uses the Event
interface, must be dispatched at the given element. The event object must have its detail
attribute set to 0.
Firing a simple event called e means that an event with the name e, in the http://www.w3.org/2001/xml-events
namespace, which does not bubble but is cancelable, and which uses the Event
interface, must be dispatched at the given element. The event object must have its detail
attribute set to 0.
Firing a show
event means firing a simple event called show
. Firing a load
event means firing a simple event called load
. Firing an error
event means firing a simple event called error
.
The default action of these event is to do nothing unless otherwise stated.
If you dispatch a custom "click" event at an element that would normally have default actions, they should get triggered. We need to go through the entire spec and make sure that any default actions are defined in terms of any event of the right type on that element, not those that are dispatched in expected ways.
We need a section to define how events all work, default actions, etc. For example, how does clicking on a span in a link that is in another link actually cause a link to be followed? which one? (where should this section be?)
The a
, area
, and link
elements can, in certain situations described in the definitions of those elements, represent hyperlinks.
The href
attribute on a hyperlink element must have a value that is a URI (or IRI). This URI is the destination resource of the hyperlink.
The href
attribute on a
and area
elements is not required; when those elements do not have href
attributes they do not represent hyperlinks.
The href
attribute on the link
element is required, but whether a link
element represents a hyperlink or not depends on the value of the rel
attribute of that element.
For a
and area
elements that represent hyperlinks, the relationship between the document containing the hyperlink and the destination resource indicated by the hyperlink is given by the value of the element's rel
attribute. The allowed values and their meanings are defined below. The rel
attribute has no default value. If the attribute is omitted or if none of the values in the attribute are recognised by the UA, then the document has no particular relationship with the destination resource other than there being a hyperlink between the two.
The media
attribute describes for which media the target document was designed. It is purely advisory. The value must be a valid media query. [MQ] The default, if the media
attribute is omitted or has an invalid value, is all
.
The hreflang
attribute on hyperlink elements, if present, gives the language of the linked resource. It is purely advisory. The value must be a valid RFC 3066 language code. [RFC3066] User agents must not consider this attribute authoritative AMPERSANDmdash; upon fetching the resource, user agents must only use language information associated with the resource to determine its language, not metadata included in the link to the resource.
The type
attribute, if present, gives the MIME type of the linked resource. It is purely advisory. The value must be a valid MIME type, optionally with parameters. [RFC2046] User agents must not consider the type
attribute authoritative AMPERSANDmdash; upon fetching the resource, user agents must only use the Content-Type information associated with the resource to determine its type, not metadata included in the link to the resource.
The ping
attribute, if present, gives the URIs of the resources that are interested in being notified if the user follows the hyperlink. The value must be a space separated list of one or more URIs. The value is used by the user agent when following hyperlinks.
following hyperlinks defined here
If an a
or area
hyperlink element has a ping
attribute and the user follows the hyperlink, the user agent must take the ping
attribute's value, strip leading and trailing spaces, split the value on sequences of spaces, treat each resulting part as a URI (resolving relative URIs according to element's base URI) and then should send a request to each of the resulting URIs. This may be done in parallel with the primary request, and is independent of the result of that request.
User agents should allow the user to adjust this behaviour, for example in conjunction with a setting that disables the sending of HTTP Referrer headers. Based on the user's preferences, UAs may either ignore the ping
attribute altogether, or selectively ignore URIs in the list (e.g. ignoring any third-party URIs).
For URIs that are HTTP URIs, the requests must be performed using the POST method (with an empty entity body in the request). User agents must ignore any entity bodies returned in the responses, but must, unless otherwise specified by the user, honour the HTTP headers AMPERSANDmdash; in particular, HTTP cookie headers. [RFC2965]
To save bandwidth, implementors might wish to consider omitting optional headers such as Accept
from these requests.
When the ping
attribute is present, user agents should clearly indicate to the user that following the hyperlink will also cause secondary requests to be sent in the background, possibly including listing the actual target URIs.
The ping
attribute is redundant with pre-existing technologies like HTTP redirects and JavaScript in allowing Web pages to track which off-site links are most popular or allowing advertisers to track click-through rates.
However, the ping
attribute provides these advantages to the user over those alternatives:
Thus, while it is possible to track users without this feature, authors are encouraged to use the ping
attribute so that the user agent can improve the user experience.
The following table summarises the link types that are defined by this specification. This table is non-normative; the actual definitions for the link types are given in the next few sections.
In this section, the term referenced document refers to the resource identified by the element representing the link, and the term current document refers to the resource within which the element representing the link finds itself.
Link type | Effect on... | Brief description | |
---|---|---|---|
link | a and area | ||
alternate | Hyperlink | Hyperlink | Gives alternate representations of the current document. |
archives | Hyperlink | Hyperlink | Provides a link to a collection of records, documents, or other materials of historical interest. |
author | Hyperlink | Hyperlink | Gives a link to the current document's author. |
bookmark | not allowed | Hyperlink | Gives the permalink for the nearest ancestor section. |
contact | Hyperlink | Hyperlink | Gives a link to contact information for the current document. |
external | not allowed | Hyperlink | Indicates that the referenced document is not part of the same site as the current document. |
feed | Hyperlink | Hyperlink | Gives the address of a syndication feed for the current document. |
first | Hyperlink | Hyperlink | Indicates that the current document is a part of a series, and that the first document in the series is the referenced document. |
help | Hyperlink | Hyperlink | Provides a link to context-sensitive help. |
icon | External Resource | not allowed | Imports an icon to represent the current document. |
index | Hyperlink | Hyperlink | Gives a link to the document that provides a table of contents or index listing the current document. |
last | Hyperlink | Hyperlink | Indicates that the current document is a part of a series, and that the last document in the series is the referenced document. |
license | Hyperlink | Hyperlink | Indicates that the current document is covered by the copyright license described by the referenced document. |
next | Hyperlink | Hyperlink | Indicates that the current document is a part of a series, and that the next document in the series is the referenced document. |
nofollow | not allowed | Hyperlink | Indicates that the current document's original author or publisher does not endorse the referenced document. |
pingback | External Resource | not allowed | Gives the address of the pingback server that handles pingbacks to the current document. |
prefetch | External Resource | not allowed | Specifies that the target resource should be pre-emptively cached. |
prev | Hyperlink | Hyperlink | Indicates that the current document is a part of a series, and that the previous document in the series is the referenced document. |
search | Hyperlink | Hyperlink | Gives a link to a resource that can be used to search through the current document and its related pages. |
stylesheet | External Resource | not allowed | Imports a stylesheet. |
sidebar | Hyperlink | Hyperlink | Specifies that the referenced document, if retrieved, is intended to be shown in the browser's sidebar (if it has one). |
tag | Hyperlink | Hyperlink | Gives a tag (identified by the given address) that applies to the current document. |
up | Hyperlink | Hyperlink | Provides a link to a document giving the context for the current document. |
Some of the types described below list synonyms for these values. These are to be handled as specified by user agents, but must not be used in documents.
alternate
"The alternate
keyword may be used with link
, a
, and area
elements. For link
elements, if the rel
attribute does not also contain the keyword stylesheet
, it creates a hyperlink; but if it does also contains the keyword stylesheet
, the alternate
keyword instead modifies the meaning of the stylesheet
keyword in the way described for that keyword, and the rest of this subsection doesn't apply.
The alternate
keyword indicates that the referenced document is an alternate representation of the current document.
The nature of the referenced document is given by the media
, hreflang
, and type
attributes.
If the alternate
keyword is used with the media
attribute, it indicates that the referenced document is intended for use with the media specified.
If the alternate
keyword is used with the hreflang
attribute, it indicates that the referenced document is a translation.
If the alternate
keyword is used with the type
attribute, it indicates that the referenced document is a reformulation of the current document in the specified format.
If the alternate
keyword is used with the type
attribute set to the value application/rss+xml
or the value application/atom+xml
, then the user agent must treat the link as it would if it had the feed
keyword specified as well.
The alternate
link relationship is transitive AMPERSANDmdash; that is, if a document links to two other documents with the link type "alternate
", then, in addition to implying that those documents are alternative representations of the first document, it is also implying that those two documents are alternative representations of each other.
archives
"The archives
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The archives
keyword indicates that the referenced document describes a collection of records, documents, or other materials of historical interest.
A blog's index page could link to an index of the blog's past posts with rel="archives"
.
Synonyms: For historical reasons, user agents must also treat the keyword "archive
" like the archives
keyword.
author
"The author
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
For a
and area
elements, the author
keyword indicates that the referenced document provides further information about the author of the section that the element defining the hyperlink applies to.
For link
elements, the author
keyword indicates that the referenced document provides further information about the author for the page as a whole.
The "referenced document" can be, and often is, a mailto:
URI giving the e-mail address of the author. [MAILTO]
Synonyms: For historical reasons, user agents must also treat link
, a
, and area
elements that have a rev
attribute with the value "made
" as having the author
keyword specified as a link relationship.
bookmark
"The bookmark
keyword may be used with a
and area
elements.
The bookmark
keyword gives a permalink for the nearest ancestor article
element of the linking element in question, or of the section the linking element is most closely associated with, if there are no ancestor article
elements.
The following snippet has three permalinks. A user agent could determine which permalink applies to which part of the spec by looking at where the permalinks are given.
... AMPERSANDlt;body> AMPERSANDlt;h1>Example of permalinksAMPERSANDlt;/h1> AMPERSANDlt;div id="a"> AMPERSANDlt;h2>First exampleAMPERSANDlt;/h2> AMPERSANDlt;p>AMPERSANDlt;a href="a.html" rel="bookmark">ThisAMPERSANDlt;/a> permalink applies to only the content from the first H2 to the second H2. The DIV isn't exactly that section, but it roughly corresponds to it.AMPERSANDlt;/p> AMPERSANDlt;/div> AMPERSANDlt;h2>Second exampleAMPERSANDlt;/h2> AMPERSANDlt;article id="b"> AMPERSANDlt;p>AMPERSANDlt;a href="b.html" rel="bookmark">ThisAMPERSANDlt;/a> permalink applies to the outer ARTICLE element (which could be, e.g., a blog post).AMPERSANDlt;/p> AMPERSANDlt;article id="c"> AMPERSANDlt;p>AMPERSANDlt;a href="c.html" rel="bookmark">ThisAMPERSANDlt;/a> permalink applies to the inner ARTICLE element (which could be, e.g., a blog comment).AMPERSANDlt;/p> AMPERSANDlt;/article> AMPERSANDlt;/article> AMPERSANDlt;/body> ...
contact
"The contact
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
For a
and area
elements, the contact
keyword indicates that the referenced document provides further contact information for the section that the element defining the hyperlink applies to.
User agents must treat any hyperlink in an address
element as having the contact
link type specified.
For link
elements, the contact
keyword indicates that the referenced document provides further contact information for the page as a whole.
external
"The external
keyword may be used with a
and area
elements.
The external
keyword indicates that the link is leading to a document that is not part of the site that the current document forms a part of.
feed
"The feed
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The feed
keyword indicates that the referenced document is a syndication feed. If the alternate
link type is also specified, then the feed is specifically the feed for the current document; otherwise, the feed is just a syndication feed, not necessarily associated with a particular Web page.
The first link
, a
, or area
element in the document (in tree order) that creates a hyperlink with the link type feed
must be treated as the default syndication feed for the purposes of feed autodiscovery.
The feed
keyword is implied by the alternate
link type in certain cases (q.v.).
The following two link
elements are equivalent: both give the syndication feed for the current page:
AMPERSANDlt;link rel="alternate" type="application/atom+xml" href="data.xml">
AMPERSANDlt;link rel="feed alternate" href="data.xml">
The following extract offers various different syndication feeds:
AMPERSANDlt;p>You can access the planets database using Atom feeds:AMPERSANDlt;/p> AMPERSANDlt;ul> AMPERSANDlt;li>AMPERSANDlt;a href="recently-visited-planets.xml" rel="feed">Recently Visited PlanetsAMPERSANDlt;/a>AMPERSANDlt;/li> AMPERSANDlt;li>AMPERSANDlt;a href="known-bad-planets.xml" rel="feed">Known Bad PlanetsAMPERSANDlt;/a>AMPERSANDlt;/li> AMPERSANDlt;li>AMPERSANDlt;a href="unexplored-planets.xml" rel="feed">Unexplored PlanetsAMPERSANDlt;/a>AMPERSANDlt;/li> AMPERSANDlt;/ul>
help
"The help
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
For a
and area
elements, the help
keyword indicates that the referenced document provides further help information for the parent of the element defining the hyperlink, and its children.
In the following example, the form control has associated context-sensitive help. The user agent could use this information, for example, displaying the referenced document if the user presses the "Help" or "F1" key.
AMPERSANDlt;p>AMPERSANDlt;label> Topic: AMPERSANDlt;input name=topic> AMPERSANDlt;a href="help/topic.html" rel="help">(Help)AMPERSANDlt;/a>AMPERSANDlt;/label>AMPERSANDlt;/p>
For link
elements, the help
keyword indicates that the referenced document provides help for the page as a whole.
icon
"The icon
keyword may be used with link
elements, for which it creates an external resource link.
The specified resource is an icon representing the page or site, and should be used by the user agent when representing the page in the user interface.
Icons could be auditory icons, visual icons, or other kinds of icons. If multiple icons are provided, the user agent must select the most appropriate icon according to the media
attribute.
license
"The license
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The license
keyword indicates that the referenced document provides the copyright license terms under which the current document is provided.
Synonyms: For historical reasons, user agents must also treat the keyword "copyright
" like the license
keyword.
nofollow
"The nofollow
keyword may be used with a
and area
elements.
The nofollow
keyword indicates that the link is not endorsed by the original author or publisher of the page.
pingback
"The pingback
keyword may be used with link
elements, for which it creates an external resource link.
For the semantics of the pingback
keyword, see the Pingback 1.0 specification. [PINGBACK]
prefetch
"The prefetch
keyword may be used with link
elements, for which it creates an external resource link.
The prefetch
keyword indicates that preemptively fetching and caching the specified resource is likely to be beneficial, as it is highly likely that the user will require this resource.
search
"The search
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The search
keyword indicates that the referenced document provides an interface specifically for searching the document and its related resources.
stylesheet
"The stylesheet
keyword may be used with link
elements, for which it creates an external resource link.
The specified resource is a resource that describes how to present the document. Exactly how the resource is to be processed depends on the actual type of the resource.
If the alternate
keyword is also specified on the link
element, then the link is an alternate stylesheet.
Need more here -- defining preferred stylesheets, alternate stylesheets, persistent stylesheets, and the stuff about the alternate stylesheet API. Maybe this should all be deferred to another processing model section.
sidebar
"The sidebar
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The sidebar
keyword indicates that the referenced document, if retrieved, is intended to be shown in a secondary browsing context (if possible), instead of in the current browsing context.
tag
"The tag
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The tag
keyword indicates that the tag that the referenced document represents applies to the current document.
Some documents form part of a hierarchical structure of documents.
A hierarchical structure of documents is one where each document can have various subdocuments. A subdocument is said to be a child of the document it is a subdocument of. The document of which it is a subdocument is said to be its parent. The children of a document have a relative order; the subdocument that precedes another is its previous sibling, and the one that follows it is its next sibling. A document with no parent forms the top of the hierarchy.
first
"The first
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The first
keyword indicates that the document is part of a hierarchical structure, and that the link is leading to the document that is the first child of the current document's parent document.
Synonyms: For historical reasons, user agents must also treat the keywords "begin
" and "start
" like the first
keyword.
index
"The index
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The index
keyword indicates that the document is part of a hierarchical structure, and that the link is leading to the document that is the top of the hierarchy.
Synonyms: For historical reasons, user agents must also treat the keywords "top
", "contents
", and "toc
" like the index
keyword.
last
"The last
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The last
keyword indicates that the document is part of a hierarchical structure, and that the link is leading to the document that is the last child of the current document's parent document.
Synonyms: For historical reasons, user agents must also treat the keyword "end
" like the last
keyword.
next
"The next
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The next
keyword indicates that the document is part of a hierarchical structure, and that the link is leading to the document that is the next sibling of the current document.
prev
"The prev
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The prev
keyword indicates that the document is part of a hierarchical structure, and that the link is leading to the document that is the previous sibling of the current document.
Synonyms: For historical reasons, user agents must also treat the keyword "previous
" like the prev
keyword.
up
"The up
keyword may be used with link
, a
, and area
elements. For link
elements, it creates a hyperlink.
The up
keyword indicates that the document is part of a hierarchical structure, and that the link is leading to the document that is the parent of the current document.
Other than the types defined above, only types defined as extensions in the WHATWG Wiki RelExtensions page may be used with the rel
attribute on link
, a
, and area
elements. [WHATWGWIKI]
Anyone is free to edit the WHATWG Wiki RelExtensions page at any time to add a type. Extension types must be specified with the following information:
The actual value being defined. The value should not be confusingly similar to any other defined value (e.g. differing only in case).
link
One of the following:
link
elements. link
element; it creates a hyperlink link. link
element; it creates a external resource link. a
and area
One of the following:
a
and area
elements. a
and area
elements; it creates a hyperlink. A short description of what the keyword's meaning is.
A link to a more detailed description of the keyword's semantics and requirements. It could be another page on the Wiki, or a link to an external page.
A list of other keyword values that have exactly the same processing requirements. Authors must not use the values defined to be synonyms, they are only intended to allow user agents to support legacy content.
One of the following:
link
" and "Effect on... a
and area
" information should be set to "not allowed". If a keyword is added with the "proposal" status and found to be redundant with existing values, it should be removed and listed as a synonym for the existing value. If a keyword is added with the "proposal" status and found to be harmful, then it should be changed to "rejected" status, and its "Effect on..." information should be changed accordingly.
Conformance checkers must use the information given on the WHATWG Wiki RelExtensions page to establish if a value not explicitly defined in this specification is allowed or not. When an author uses a new type not defined by either this specification or the Wiki page, conformance checkers should offer to add the value to the Wiki, with the details described above, with the "proposal" status.
This specification does not define how new values will get approved. It is expected that the Wiki will have a community that addresses this.
...image map, valid area, usemap
, coords
, shape
, server side image map.
default action of clicking an image is to check if target was an image with usemap; if so, fire DOMActivate on the matching area
, otherwise do nothing. (Or, do click events clicked on areas fire directly on the area and not on the img?)
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:
Commands are represented by elements in the DOM. Any element that can define a command also implements the Command
interface:
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 simply 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 an absolute URI to 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
.
a
element to define a commandAn 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 a
element. If the attribute is not present, the Hint is the empty string.
The Icon of the command is the absolute URI of the first image in the element. Specifically, in a depth-first search of the children of the element, the first element that is img
element with a src
attribute is the one that is used as the image. The URI must be taken from the element's src
attribute. Relative URIs must be resolved relative to the base URI of the image element. If no image is found, then the Icon facet is left blank.
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.
button
element to define a commandA 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).
input
element to define a commandAn 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.
option
element to define a commandAn 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.
command
element to define a commandA 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 URI resulting from resolving the value of the element's icon
attribute as a URI relative to the element's base URI. If the element has no icon
attribute then the command has no Icon.
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 behaviour described in the definition of the click()
method of the HTMLCommandElement
interface.
This section is non-normative.
...
A menu consists of a list of zero or more of the following components:
The list corresponding to a particular element is built by iterating over its child nodes.
For each child node in tree order, the required behaviour depends on what the node is, as follows:
command
element with a default
attribute, mark the command as being a default command. hr
element 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) li
element li
element. menu
element with no label
attribute select
element menu
or select
element, then append another separator. menu
element with a label
attribute optgroup
element 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. Once all the nodes have been processed as described above, the user agent must the post-process the menu as follows:
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.
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, as defined above.
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.
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.
See WF2 for now
This section describes a set of APIs that allow authors to make their documents and applications interact with the user agent, integrating with native features such as the navigation history, drag-and-drop, undo/redo, and selections.
Many of the APIs are part of the WindowHTML
interface. The WindowHTML
interface must be obtainable from the Window
object using binding-specific casting methods. [WINDOW]
interface WindowHTML { // defined in this section readonly attribute History history; readonly attribute ClientInformation navigator; readonly attribute UndoManager undoManager; Selection getSelection(); readonly attribute Storage sessionStorage; readonly attribute StorageList globalStorage; // defined in other sections attribute Object onerror; // more...};
The WindowHTML
object must provide the following constructors:
Audio()
Constructs an Audio
object.
Image()
Image(in unsigned long w)
Image(in unsigned long w, in unsigned long h)
Constructs an HTMLImageElement
object (a new img
element). If the h argument is present, the new object's height
content attribute must be set to h. If the w argument is present, the new object's width
content attribute must be set to w.
Option()
Option(in DOMString name)
Option(in DOMString name, in DOMString value)
Constructs an HTMLOptionElement
object (a new option
element). need to define argument processing
History
objects provide a representation of the pages in the session history of their Window
object's browsing context. Each browsing context (frame
, iframe
, etc) has a distinct session history.
Each DocumentUI
object in a browsing context's session history is associated with a unique instance of the History
object, although they all must model the same underlying session history.
The history
attribute of the WindowHTML
interface must return the object implementing the History
interface for that WindowHTML
object's associated DocumentUI
object.
History
objects represent their browsing context's session history as a flat list of URIs and state objects. (This does not imply that the UI need be linear. See the notes below.)
Typically, the history list will consist of only URIs. However, a page can add state objects between its entry in the session history and the next ("forward") entry. These are then returned to the script when the user (or script) goes back in the history, thus enabling authors to use the "navigation" metaphor even in one-page applications.
Entries that consist of state objects share the same DocumentUI
as the entry for the URI itself. Contiguous entries that differ just by fragment identifier must also share the same DocumentUI
.
All entries that share the same DocumentUI
(and that are therefore merely different states of one particular document) are contiguous by definition.
At any point, one of the entries in the session history is the current entry. This is the entry representing the page in this browsing context that is considered the "current" page by the UA. The current entry is usually an entry for the location of the DocumentUI
. However, it can also be one of the entries for state objects added to the history by that document.
When the browser's navigation model differs significantly from the sequential model represented by the History
interface, for example if separate DocumentUI
objects in the session history are all simulatenously displayed and active, then the current entry could even be an entry unrelated to the History
object's own DocumentUI
object. If, when a method is invoked on a History
object, the current entry for that browsing context's session history has a different DocumentUI
object than the History
object's own DocumentUI
object, then the user agent must raise a NO_MODIFICATION_ALLOWED_ERR
DOM exception. (This can only happen if scripts are allowed to run in documents that are not the current document. Typically, however, user agents only allow scripts from the current entry to execute.)
User agents may discard the DOMs of entries other than the current entry, reloading the pages afresh when the user or script navigates back to such pages. This specification does not specify when user agents should discard pages' DOMs and when they should cache them. See the section on the load
and unload
events for more details.
Entries that have had their DOM discarded must, for the purposes of the algorithms given below, act as if they had not. When the user or script navigates back or forwards to a page which has no in-memory DOM objects, any other entries that shared the same DocumentUI
object with it must share the new object as well.
When a user agent discards the DOM from an entry in the session history, it must also discard all the entries from the first state object entry for that DocumentUI
object up to and including the last entry for that DocumentUI
object (including any non-state-object entries in that range, such as entries where the user navigated using fragment identifiers). These entries are not recreated if the user or script navigates back to the page. If there are no state object entries for that DocumentUI
object then no entries are removed.
History
interfaceinterface History { readonly attribute long length; void go(in long delta); void go(); void back(); void forward(); void pushState(in DOMObject data); void clearState();};
The length
attribute of the History
interface must return the number of entries in this session history.
The actual entries are not accessible from script.
The go(delta)
method causes the UA to move the number of steps specified by delta in the session history.
If the index of the current entry plus delta is less than zero or greater than or equal to the number of items in the session history, then the user agent must do nothing.
If the delta is zero, then the user agent must act as if the location.reload()
method was called instead.
Otherwise, the user agent must cause the current browsing context to navigate to the specified entry, as described below. The specified entry is the one whose index equals the index of the current entry plus delta.
If there are any entries with state objects between the current entry and the specified entry (not inclusive), then the user agent must iterate through every entry between the current entry and the specified entry, starting with the entry closest to the current entry, and ending with the one closest to the specified entry. For each entry, if the entry is a state object, the user agent must activate the state object.
If the specified entry has a different DocumentUI
object than the current entry then the user agent must make that DocumentUI
object the user's "current" one for that browsing context.
If the specified entry is a state object, the user agent must activate that state object. Otherwise, the user agent must update the current location object to the new location.
User agents may also update other aspects of the document view when the location changes in this way, for instance the scroll position, values of form fields, etc.
When the user navigates through a browsing context, e.g. using a browser's back and forward buttons, the user agent must translate this action into the equivalent invocations of the history.go(delta)
method on the various affected window
objects.
Some of the other members of the History
interface are defined in terms of the go()
method, as follows:
Member | Definition |
---|---|
go() | Must do the same as go(0) |
back() | Must do the same as go(-1) |
forward() | Must do the same as go(1) |
The pushState(data)
method adds a state object to the history.
When this method is invoked, the user agent must first remove from the session history any entries for that DocumentUI
from the entry after the current entry up to the last entry in the session history that references the same DocumentUI
object, if any. If the current entry is the last entry in the session history, or if there are no entries after the current entry that reference the same DocumentUI
object, then no entries are removed.
Then, the user agent must add a state object entry to the session history, after the current entry, with the specified data as the state object.
Finally, the user agent must update the current entry to be the this newly added entry.
There has been a suggestion that pushState() should take a URI and a string; the URI to allow for the page to be bookmarked, and the string to allow the UA to give the page a meaningful title in the history state, if it shows history state.
User agents may limit the number of state objects added to the session history per page. If a page hits the UA-defined limit, user agents must remove the entry immediately after the first entry for that DocumentUI
object in the session history after having added the new entry. (Thus the state history acts as a FIFO buffer for eviction, but as a LIFO buffer for navigation.)
The clearState()
method removes all the state objects for the DocumentUI
object from the session history.
When this method is invoked, the user agent must remove from the session history all the entries from the first state object entry for that DocumentUI
object up to the last entry that references that same DocumentUI
object, if any.
Then, if the current entry was removed in the previous step, the current entry must be set to the last entry for that DocumentUI
object in the session history.
When a state object in the session history is activated (which happens in the cases described above), the user agent must fire a popstate
event in the http://www.w3.org/2001/xml-events
namespace on the the body element using the PopStateEvent
interface, with the state object in the state
attribute. This event bubbles but is not cancelable and has no default action.
interface PopStateEvent : Event { readonly attribute DOMObject state; void initPopStateEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMObject statetArg); void initPopStateEventNS(in DOMString namespaceURIArg, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMObject stateArg);};
The initPopStateEvent()
and initPopStateEventNS()
methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
The state
attribute represents the context information for the event.
Location
interfaceThe location
attribute of the WindowHTML
interface must return an object implementing the Location
interface.
For historical reasons, the location
attribute of the DocumentUI
interface must return the same object as the location
attribute on its associated WindowHTML
object.
Location
objects provide a representation of the URI of their document, and allow the current entry of the browsing context's session history to be changed, by adding or replacing entries in the history
object.
interface Location { readonly attribute DOMString hash; readonly attribute DOMString host; readonly attribute DOMString hostname; readonly attribute DOMString href; readonly attribute DOMString pathname; readonly attribute DOMString port; readonly attribute DOMString protocol; readonly attribute DOMString search; void assign(in DOMString url); void replace(in DOMString url); void reload();};
In the ECMAScript DOM binding, objects implementing this interface must stringify to the same value as the href
attribute.
In the ECMAScript DOM binding, the location
members of the DocumentUI
and WindowHTML
interfaces behave as if they had a setter: user agents must treats attempts to set these location
attribute as attempts at setting the href
attribute of the relevant Location
object instead.
The href
attribute returns the address of the page represented by the associated DocumentUI
object, as an absolute IRI reference.
On setting, the user agent must act as if the assign()
method had been called with the new value as its argument.
When the assign(url)
method is invoked, the UA must remove all the entries after the current entry in its DocumentUI
's History
object, add a new entry, with the given url, at the end of the list (asynchronously loading the new page if necessary), and then advance to that page as if the history.forward()
method had been invoked.
When the replace(url)
method is invoked, the UA must act as if the assign()
method had been invoked, but with the additional step of removing the entry that was the current entry before the method call after the above steps (thus simply causing the current page to be replaced by the new one).
In both cases, if the location before the method call would differ from the location after the method only in terms of the fragment identifier, then the user agent must use the same DocumentUI
object, updating only the scroll position in the document's view(s) appropriately.
Relative url arguments for assign()
and replace()
must be resolved relative to the base URI of the script that made the method call.
The component parts and .reload() are yet to be defined. If anyone can come up with a decent definition, let me know.
This section is non-normative.
The History
interface is not meant to place restrictions on how implementations represent the session history to the user.
For example, session history could be implemented in a tree-like manner, with each page having multiple "forward" pages. This specification doesn't define how the linear list of pages in the history
object are derived from the actual session history as seen from the user's perspective.
Similarly, a page containing two iframe
s has a history
object distinct from the iframe
s' history
objects, despite the fact that typical Web browsers present the user with just one "Back" button, with a session history that interleaves the navigation of the two inner frames and the outer page.
Security: It is suggested that to avoid letting a page "hijack" the history navigation facilities of a UA by abusing pushState()
, the UA provide the user with a way to jump back to the previous page (rather than just going back to the previous state). For example, the back button could have a drop down showing just the pages in the session history, and not showing any of the states. Similarly, an aural browser could have two "back" commands, one that goes back to the previous state, and one that jumps straight back to the previous page.
In addition, a user agent could ignore calls to pushState()
that are invoked on a timer, or from event handlers that do not represent a clear user action, or that are invoked in rapid succession.
The navigator
attribute of the WindowHTML
interface must return an instance of the ClientInformation
interface, which represents the identity and state of the user agent (the client), and allows Web pages to register themselves as potential protocol and content handlers:
interface ClientInformation { readonly attribute boolean onLine; void registerProtocolHandler(in DOMString protocol, in DOMString uri, in DOMString title); void registerContentHandler(in DOMString mimeType, in DOMString uri, in DOMString title);};
The navigator.onLine
attribute must return false if the user agent will not contact the network when the user follows links or when a script requests a remote page (or knows that such an attempt would fail), and must return true otherwise.
The offline
event must be fired when the value of the navigator.onLine
attribute of the WindowHTML
changes from true to false.
The online
event must be fired when the value of the navigator.onLine
attribute of the WindowHTML
changes from false to true.
These events are in the http://www.w3.org/2001/xml-events
namespace, do bubble, are not cancelable, have no default action, and use the normal Event
interface. They must be fired on the body element. (As the events bubble, they will reach the WindowHTML
object.)
The registerProtocolHandler()
method allows Web sites to register themselves as possible handlers for particular protocols. For example, an online fax service could register itself as a handler of the fax:
protocol ([RFC2806]), so that if the user clicks on such a link, he is given the opportunity to use that Web site. Analogously, the registerContentHandler()
method allows Web sites to register themselves as possible handlers for content in a particular MIME type. For example, the same online fax service could register itself as a handler for image/g3fax
files ([RFC1494]), so that if the user has no native application capable of handling G3 Facsimile byte streams, his Web browser can instead suggest he use that site to view the image.
User agents may, within the constraints described in this section, do whatever they like when the methods are called. A UA could, for instance, prompt the user and offer the user the opportunity to add the site to a shortlist of handlers, or make the handlers his default, or cancel the request. UAs could provide such a UI through modal UI or through a non-modal transient notification interface. UAs could also simply silently collect the information, providing it only when relevant to the user.
There is an example of how these methods could be presented to the user below.
The arguments to the methods have the following meanings:
registerProtocolHandler()
only) A scheme, such as ftp
or fax
. The scheme must be treated case-insensitively by user agents for the purposes of comparing with the scheme part of URIs that they consider against the list of registered handlers.
The protocol value, if it contains a colon (as in "ftp:
"), will never match anything, since schemes don't contain colons.
registerContentHandler()
only) A MIME type, such as model/vrml
or text/richtext
. The MIME type must be treated case-insensitively by user agents for the purposes of comparing with MIME types of documents that they consider against the list of registered handlers.
User agents must compare the given values only to the MIME type/subtype parts of content types, not to the complete type including parameters. Thus, if mimeType values passed to this method include characters such as commas or whitespace, or include MIME parameters, then the handler being registered will never be used.
The URI of the page that will handle the requests. When the user agent uses this URI, it must replace the first occurrence of the exact literal string "%s
" with an escaped version of the URI of the content in question (as defined below), and then fetch the resulting URI using the GET method (or equivalent for non-HTTP URIs).
To get the escaped version of the URI, first, the domain part of the URI (if any) must be converted to its punycode representation, and then, every character in the URI that is not in the ranges given in the next paragraph must be replaced by its UTF-8 byte representation, each byte being represented by a U+0025 (%) character and two digits in the range U+0030 (0) to U+0039 (9) and U+0041 (A) to U+0046 (F) giving the hexadecimal representation of the byte.
The ranges of characters that must not be escaped are: U+002D (-), U+002E (.), U+0030 (0) to U+0039 (9), U+0041 (A) to U+005A (Z), U+005F (_), U+0061 (a) to U+007A (z), and U+007E (~).
If the user had visited a site that made the following call:
navigator.registerContentHandler('application/x-soup', 'http://example.com/soup?url=%s', 'SoupWebAMPERSANDtrade;')
...and then clicked on a link such as:
AMPERSANDlt;a href="http://www.example.net/chickenkAMPERSAND#xEF;wi.soup">Download our Chicken Kiwi soup!AMPERSANDlt;/a>
...then, assuming this chickenkiwi.soup
file was served with the MIME type application/x-soup
, the UA might instead navigate to the following URI:
http://example.com/soup?url=http%3A%2F%2Fwww.example.net%2Fchickenk%C3%AFwi.soup
This site could then fetch the chickenkiwi.soup
file and do whatever it is that it does with soup (synthesise it and ship it to the user, or whatever).
A descriptive title of the handler, which the UA might use to remind the user what the site in question is.
User agents should raise security exceptions if the methods are called with protocol or mimeType values that the UA deems to be "privileged". For example, a site attempting to register a handler for http
URIs or text/html
content in a Web browser would likely cause an exception to be raised.
User agents must raise a SYNTAX_ERR
exception if the uri argument passed to one of these methods does not contain the exact literal string "%s
".
User agents must not raise any other exceptions (other than binding-specific exceptions, such as for an incorrect number of arguments in an ECMAScript implementation).
This section does not define how the pages registered by these methods are used, beyond the requirements on how to process the uri value (see above). To some extent, the processing model for navigating across documents defines some cases where these methods are relevant, but in general UAs may use this information wherever they would otherwise consider handing content to native plugins or helper applications.
UAs must not use registered content handlers to handle content that was returned as part of a non-GET transaction (or rather, as part of any non-idempotent transaction), as the remote site would not be able to fetch the same data.
These mechanisms can introduce a number of concerns, in particular privacy concerns.
Hijacking all Web usage. User agents should not allow protocols that are key to its normal operation, such as http
or https
, to be rerouted through third-party sites. This would allow a user's activities to be trivially tracked, and would allow user information, even in secure connections, to be collected.
Hijacking defaults. It is strongly recommended that user agents do not automatically change any defaults, as this could lead the user to send data to remote hosts that the user is not expecting. New handlers registering themselves should never automatically cause those sites to be used.
Registration spamming. User agents should consider the possibility that a site will attempt to register a large number of handlers, possibly from multiple domains (e.g. by redirecting through a series of pages each on a different domain, and each registering a handler for video/mpeg
AMPERSANDmdash; analogous practices abusing other Web browser features have been used by pornography Web sites for many years). User agents should gracefully handle such hostile attempts, protecting the user.
Misleading titles. User agents should not rely wholy on the title argument to the methods when presenting the registered handlers to the user, since sites could easily lie. For example, a site hostile.example.net
could claim that it was registering the "Cuddly Bear Happy Content Handler". User agents should therefore use the handler's domain in any UI along with any title.
Hostile handler metadata. User agents should protect against typical attacks against strings embedded in their interface, for example ensuring that markup or escape characters in such strings are not executed, that null bytes are properly handled, that over-long strings do not cause crashes or buffer overruns, and so forth.
Leaking Intranet URIs. The mechanism described in this section can result in secret Intranet URIs being leaked, in the following manner:
No actual confidential file data is leaked in this manner, but the URIs themselves could contain confidential information. For example, the URI could be https://www.corp.example.com/upcoming-aquisitions/samples.egf
, which might tell the third party that Example Corporation is intending to merge with Samples LLC. Implementors might wish to consider allowing administrators to disable this feature for certain subdomains, content types, or protocols.
Leaking secure URIs. User agents should not send HTTPS URIs to third party sites registered as content handlers, in the same way that user agents do not send Referer
headers from secure sites to third party sites.
Leaking credentials. User agents must never send username or password information in the URIs that are escaped and included sent to the handler sites. User agents may even avoid attempting to pass to Web-based handlers the URIs of resources that are known to require authentication to access, as such sites would be unable to access the resources in question without prompting the user for credentials themselves (a practice that would require the user to know whether to trust the third party handler, a decision many users are unable to make or even understand).
This section is non-normative.
A simple implementation of this feature for a desktop Web browser might work as follows.
The registerProtocolHandler()
method could display a modal dialog box:
||[ Protocol Handler Registration ]|||||||||||||||||||||||||||| || This Web page: || || Kittens at work || http://kittens.example.org/ || || ...would like permission to handle the protocol "x-meow:" || using the following Web-based application: || || Kittens-at-work displayer || http://kittens.example.org/?show=%s || || Do you trust the administrators of the "kittens.example. || org" domain? || || ( Trust kittens.example.org ) (( Cancel )) ||____________________________________________________________|
...where "Kittens at work" is the title of the page that invoked the method, "http://kittens.example.org/" is the URI of that page, "x-meow" is the string that was passed to the registerProtocolHandler()
method as its first argument (protocol), "http://kittens.example.org/?show=%s" was the second argument (uri), and "Kittens-at-work displayer" was the third argument (title).
If the user clicks the Cancel button, then nothing further happens. If the user clicks the "Trust" button, then the handler is remembered.
When the user then attempts to fetch a URI that uses the "x-meow:" scheme, then it might display a dialog as follows:
||[ Unknown Protocol ]||||||||||||||||||||||||||||||||||||||||| || You have attempted to access: || || x-meow:S2l0dGVucyBhcmUgdGhlIGN1dGVzdCE%3D || || How would you like FerretBrowser to handle this resource? || || (o) Contact the FerretBrowser plugin registry to see if || there is an official way to handle this resource. || || ( ) Pass this URI to a local application: || [ /no application selected/ ] ( Choose ) || || ( ) Pass this URI to the "Kittens-at-work displayer" || application at "kittens.example.org". || || [ ] Always do this for resources using the "x-meow" || protocol in future. || || ( Ok ) (( Cancel )) ||____________________________________________________________|
...where the third option is the one that was primed by the site registering itself earlier.
If the user does select that option, then the browser, in accordance with the requirements described in the previous two sections, will redirect the user to "http://kittens.example.org/?show=x-meow%3AS2l0dGVucyBhcmUgdGhlIGN1dGVzdCE%253D".
The registerContentHandler()
method would work equivalently, but for unknown MIME types instead of unknown protocols.
This section is non-normative.
This specification introduces two related mechanisms, similar to HTTP session cookies [RFC2965], for storing structured data on the client side.
The first is designed for scenarios where the user is carrying out a single transaction, but could be carrying out multiple transactions in different windows at the same time.
Cookies don't really handle this case well. For example, a user could be buying plane tickets in two different windows, using the same site. If the site used cookies to keep track of which ticket the user was buying, then as the user clicked from page to page in both windows, the ticket currently being purchased would "leak" from one window to the other, potentially causing the user to buy two tickets for the same flight without really noticing.
To address this, this specification introduces the sessionStorage
DOM attribute. Sites can add data to the session storage, and it will be accessible to any page from that domain opened in that window.
For example, a page could have a checkbox that the user ticks to indicate that he wants insurance:
AMPERSANDlt;label> AMPERSANDlt;input type="checkbox" onchange="sessionStorage.insurance = checked"> I want insurance on this trip.AMPERSANDlt;/label>
A later page could then check, from script, whether the user had checked the checkbox or not:
if (sessionStorage.insurance) { ... }
If the user had multiple windows opened on the site, each one would have its own individual copy of the session storage object.
The second storage mechanism is designed for storage that spans multiple windows, and lasts beyond the current session. In particular, Web applications may wish to store megabytes of user data, such as entire user-authored documents or a user's mailbox, on the clientside for performance reasons.
Again, cookies do not handle this case well, because they are transmitted with every request.
The globalStorage
DOM attribute is used to access the global storage areas.
The site at example.com can display a count of how many times the user has loaded its page by putting the following at the bottom of its page:
AMPERSANDlt;p> You have viewed this page AMPERSANDlt;span id="count">an untold number ofAMPERSANDlt;/span> time(s).AMPERSANDlt;/p>AMPERSANDlt;script> var storage = globalStorage['example.com']; if (!storage.pageLoadCount) storage.pageLoadCount = 0; storage.pageLoadCount = parseInt(storage.pageLoadCount, 10) + 1; document.getElementById('count').textContent = storage.pageLoadCount;AMPERSANDlt;/script>
Each domain and each subdomain has its own separate storage area. Subdomains can access the storage areas of parent domains, and domains can access the storage areas of subdomains.
globalStorage['']
is accessible to all domains. globalStorage['com']
is accessible to all .com domains globalStorage['example.com']
is accessible to example.com and any of its subdomains globalStorage['www.example.com']
is accessible to www.example.com and example.com, but not www2.example.com. Storage areas (both session storage and global storage) store strings. To store structured data in a storage area, you must first convert it to a string.
Storage
interfaceinterface Storage { readonly attribute unsigned long length; DOMString key(in unsigned long index); StorageItem getItem(in DOMString key); void setItem(in DOMString key, in DOMString data); void removeItem(in DOMString key);};
Each Storage
object provides access to a list of key/value pairs, which are sometimes called items. Keys are strings, and any string (including the empty string) is a valid key. Values are strings with associated metadata, represented by StorageItem
objects.
Each Storage
object is associated with a list of key/value pairs when it is created, as defined in the sections on the sessionStorage
and globalStorage
attributes. Multiple separate objects implementing the Storage
interface can all be associated with the same list of key/value pairs simultaneously.
Key/value pairs have associated metadata. In particular, a key/value pair can be marked as either "safe only for secure content", or as "safe for both secure and insecure content".
A key/value pair is accessible if either it is marked as "safe for both secure and insecure content", or it is marked as "safe only for secure content" and the script in question is running in a secure scripting context.
The length
attribute must return the number of key/value pairs currently present and accessible in the list associated with the object.
The key(n)
method must return the name of the nth accessible key in the list. The order of keys is user-agent defined, but must be consistent within an object between changes to the number of keys. (Thus, adding or removing a key may change the order of the keys, but merely changing the value of an existing key must not.) If n is less than zero or greater than or equal to the number of key/value pairs in the object, then this method must raise an INDEX_SIZE_ERR
exception.
The getItem(key)
method must return the StorageItem
object representing the key/value pair with the given key. If the given key does not exist in the list associated with the object, or is not accessible, then this method must return null. Subsequent calls to this method with the same key from scripts running in the same security context must return the same instance of the StorageItem
interface. (Such instances must not be shared across security contexts, though.)
The setItem(key, value)
method must first check if a key/value pair with the given key already exists in the list associated with the object.
If it does not, then a new key/value pair must be added to the list, with the given key and value, such that any current or future StorageItem
objects referring to this key/value pair will return the value given in the value argument. If the script setting the value is running in a secure scripting context, then the key/value pair must be marked as "safe only for secure content", otherwise it must be marked as "safe for both secure and insecure content".
If the given key does exist in the list, then, if the key/value pair with the given key is accessible, it must have its value updated so that any current or future StorageItem
objects referring to this key/value pair will return the value given in the value argument. If it is not accessible, the method must raise a security exception.
When the setItem()
method is successfully invoked (i.e. when it doesn't raise an exception), events are fired on other HTMLDocument
objects that can access the newly stored data, as defined in the sections on the sessionStorage
and globalStorage
attributes.
The removeItem(key)
method must cause the key/value pair with the given key to be removed from the list associated with the object, if it exists and is accessible. If no item with that key exists, the method must do nothing. If an item with that key exists but is not accessible, the method must raise a security exception.
The setItem()
and removeItem()
methods must be atomic with respect to failure. That is, changes to the data storage area must either be successful, or the data storage area must not be changed at all.
In the ECMAScript DOM binding, enumerating a Storage
object must enumerate through the currently stored and accessible keys in the list the object is associated with. (It must not enumerate the values or the actual members of the interface). In the ECMAScript DOM binding, Storage
objects must support dereferencing such that getting a property that is not a member of the object (i.e. is neither a member of the Storage
interface nor of Object
) must invoke the getItem()
method with the property's name as the argument, and setting such a property must invoke the setItem()
method with the property's name as the first argument and the given value as the second argument.
StorageItem
interfaceItems in Storage
objects are represented by objects implementing the StorageItem
interface.
interface StorageItem { attribute boolean secure; attribute DOMString value;};
In the ECMAScript DOM binding, StorageItem
objects must stringify to their value
attribute's value.
The value
attribute must return the current value of the key/value pair represented by the object. When the attribute is set, the user agent must invoke the setItem()
method of the Storage
object that the StorageItem
object is associated with, with the key that the StorageItem
object is associated with as the first argument, and the new given value of the attribute as the second argument.
StorageItem
objects must be live, meaning that as the underlying Storage
object has its key/value pairs updated, the StorageItem
objects must always return the actual value of the key/value pair they represent.
If the key/value pair has been deleted, the StorageItem
object must act as if its value was the empty string. On setting, the key/value pair will be recreated.
The secure
attribute must raise an INVALID_ACCESS_ERR
exception when accessed or set from a script whose script context is not considered secure. (Basically, if the page is not an SSL page.)
If the scripting context is secure, then the secure
attribute must return true if the key/value pair is considered "safe only for secure content", and false if it is considered "safe for both secure and insecure content". If it is set to true, then the key/value pair must be flagged as "safe only for secure content". If it is set to false, then the key/value pair must be flagged as "safe for both secure and insecure content".
If a StorageItem
object is obtained by a script that is not running in a secure scripting context, and the item is then marked with the "safe only for secure content" flag by a script that is running in a secure context, the StorageItem
object must continue to be available to the first script, who will be able to read the value of the object. However, any attempt to set the value would then start raising exceptions as described in the previous section, and the key/value pair would no longer appear in the appropriate Storage
object.
sessionStorage
attributeThe sessionStorage
attribute represents the storage area specific to the current top-level browsing context.
Each top-level browsing context has a unique set of session storage areas, one for each domain.
User agents should not expire data from a browsing context's session storage areas, but may do so when the user requests that such data be deleted, or when the UA detects that it has limited storage space, or for security reasons. User agents should always avoid deleting data while a script that could access that data is running. When a top-level browsing context is destroyed (and therefore permanently inaccessible to the user) the data stored in its session storage areas can be discarded with it, as the API described in this specification provides no way for that data to ever be subsequently retrieved.
The lifetime of a browsing context can be unrelated to the lifetime of the actual user agent process itself, as the user agent may support resuming sessions after a restart.
When a new HTMLDocument
is created, the user agent must check to see if the document's top-level browsing context has allocated a session storage area for that document's domain. If it has not, a new storage area for that document's domain must be created.
The Storage
object for the document's associated WindowHTML
object's sessionStorage
attribute must then be associated with the domain's session storage area.
When a new top-level browsing context is created by cloning an existing browsing context, the new browsing context must start with the same session storage areas as the original, but the two sets must from that point on be considered separate, not affecting each other in any way.
When a new top-level browsing context is created by a script in an existing browsing context, or by the user following a link in an existing browsing context, or in some other way related to a specific HTMLDocument
, then, if the new context's first HTMLDocument
has the same domain as the HTMLDocument
from which the new context was created, the new browsing context must start with a single session storage area. That storage area must be a copy of that domain's session storage area in the original browsing context, which from that point on must be considered separate, with the two storage areas not affecting each other in any way.
When the setItem()
method is called on a Storage
object x that is associated with a session storage area, then, if the method does not raise a security exception, in every HTMLDocument
object whose WindowHTML
object's sessionStorage
attribute's Storage
object is associated with the same storage area, other than x, a storage
event must be fired, as described below.
globalStorage
attributeinterface StorageList { Storage namedItem(in DOMString domain);};
The globalStorage
object provides a Storage
object for each domain.
In the ECMAScript DOM binding, StorageList
objects must support dereferencing such that getting a property that is not a member of the object (i.e. is neither a member of the StorageList
interface nor of Object
) must invoke the namedItem()
method with the property's name as the argument.
User agents must have a set of global storage areas, one for each domain.
User agents should only expire data from the global storage areas for security reasons or when requested to do so by the user. User agents should always avoid deleting data while a script that could access that data is running. Data stored in global storage areas should be considered potentially user-critical. It is expected that Web applications will use the global storage areas for storing user-written documents.
The namedItem(domain)
method tries to returns a Storage
object associated with the given domain, according to the rules that follow.
The domain must first be split into an array of strings, by splitting the string at "." characters (U+002E FULL STOP). If the domain argument is the empty string, then the array is empty as well. If the domain argument is not empty but has no dots, then the array has one item, which is equal to the domain argument. If the domain argument contains consecutive dots, there will be empty strings in the array (e.g. the string "hello..world" becomes split into the three strings "hello", "", and "world", with the middle one being the empty string).
Each component of the array must then have the IDNA ToASCII algorithm applied to it, with both the AllowUnassigned and UseSTD3ASCIIRules flags set. [RFC3490] If ToASCII fails to convert one of the components of the string, e.g. because it is too long or because it contains invalid characters, then the user agent must raise a SYNTAX_ERR
exception. [DOM3CORE] The components after this step consist of only US-ASCII characters.
The components of the array must then be converted to lowercase. Since only US-ASCII is involved at this step, this only requires converting characters in the range A-Z to the corresponding characters in the range a-z.
The resulting array is used in a comparison with another array, as described below. In addition, its components are concatenated together, each part separated by a dot (U+002E), to form the normalised requested domain.
If the original domain was "AMPERSANDAring;sgAMPERSANDaring;rd.Example.Com", then the resulting array would have the three items "xn--sgrd-poac", "example", and "com", and the normalised requested domain would be "xn--sgrd-poac.example.com".
Next, the script's own domain is processed to find if it is allowed to access the requested domain.
If the script's domain name in not known, e.g. if only the server's IP address is known, and the normalised requested domain is not the empty string, then the user agent must raise a security exception.
If the normalised requested domain is the empty string, then the rest of this algorithm can be skipped. This is because in that situation, the comparison of the two arrays below will always find them to be the same AMPERSANDmdash; the first array in such a situation is also empty and so permission to access that storage area will always be given.
If the script's domain contains no dots (U+002E) then the string ".localdomain
" must be appended to the script's domain.
Then, the script's domain must be turned into an array, being split, converted to ASCII, and lowercased as described for the domain argument above.
Of the two arrays, the longest one must then be shortened to the length of the shorter one, by dropping items from the start of the array.
If the domain argument is "www.example.com" and the script's domain is "example.com" then the first array will be a three item array ("www", "example", "com"), and the second will be a two item array ("example", "com"). The first array is therefore shortened, dropping the leading parts, making both into the same array ("example", "com").
If the two arrays are not component-for-component identical in literal string comparisons, then the user agent must then raise a security exception.
Otherwise, the user agent must check to see if it has allocated global storage area for the normalised requested domain. If it has not, a new storage area for that domain must be created.
The user agent must then create a Storage
object associated with that domain's global storage area, and return it.
When the requested domain is a top level domain, or the empty string, or a country-specific sub-domain like "co.uk" or "ca.us", the associated global storage area is known as public storage area
The setItem()
method might be called on a Storage
object that is associated with a global storage area for a domain d, created by a StorageList
object associated with a WindowHTML
object x. Whenever this occurs, if the method didn't raise an exception, a storage
event must be fired, as described below, in every HTMLDocument
object that matches the following conditions:
WindowHTML
object is not x, and WindowHTML
object's globalStorage
attribute's StorageList
object's namedItem()
method would not raise a security exception according to the rules above if it was invoked with the domain d. In other words, every other document that has access to that domain's global storage area is notified of the change.
storage
eventThe storage
event is fired in an HTMLDocument
when a storage area changes, as described in the previous two sections (for session storage, for global storage).
When this happens, a storage
event in the http://www.w3.org/2001/xml-events
namespace, which bubbles, is not cancelable, has no default action, and which uses the StorageEvent
interface described below, must be fired on the body element.
However, it is possible (indeed, for session storage areas, likely) that the target HTMLDocument
object is not active at that time. For example, it might not be the current entry in the session history; user agents typically stop scripts from running in pages that are in the history. In such cases, the user agent must instead delay the firing of the event until such time as the HTMLDocument
object in question becomes active again.
When there are multiple delayed storage
events for the same HTMLDocument
object, user agents should coalesce events with the same domain
value (dropping duplicates).
If the DOM of a page that has delayed storage
events queued up is discarded, then the delayed events are dropped as well.
interface StorageEvent : Event { readonly attribute DOMString domain; void initStorageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString domainArg); void initStorageEventNS(in DOMString namespaceURIArg, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString domainArg);};
The initStorageEvent()
and initStorageEventNS()
methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
The domain
attribute of the StorageEvent
event object must be set to the name of the domain associated with the storage area that changed if that storage area is a global storage area, or the string "#session
" if it was a session storage area.
User agents should limit the total amount of space allowed for a domain based on the domain of the page setting the value.
User agents should not limit the total amount of space allowed on a per-storage-area basis, otherwise a site could just store data in any number of subdomains, e.g. storing up to the limit in a1.example.com, a2.example.com, a3.example.com, etc, circumventing per-domain limits.
User agents should consider additional quota mechanisms (for example limiting the amount of space provided to a domain's subdomains as a group) so that hostile authors can't run scripts from multiple subdomains all adding data to the global storage area in an attempted denial-of-service attack.
User agents may prompt the user when per-domain space quotas are reached, allowing the user to grant a site more space. This enables sites to store many user-created documents on the user's computer, for instance.
User agents should allow users to see how much space each domain is using.
If the storage area space limit is reached during a setItem()
call, the user agent should raise an exception.
A mostly arbitrary limit of five megabytes per domain is recommended. Implementation feedback is welcome and will be used to update this suggestion in future.
Multiple browsing contexts must be able to access the global storage areas simultaneously in a predictable manner. Scripts must not be able to detect any concurrent script execution.
This is required to guarentee that the length
attribute of a Storage
object never changes while a script is executing, other than in a way that is predictable by the script itself.
There are various ways of implementing this requirement. One is that if a script running in one browsing context accesses a global storage area, the UA blocks scripts in other browsing contexts when they try to access any global storage area until the first script has executed to completion. (Similarly, when a script in one browsing context accesses its session storage area, any scripts that have the same top level browsing context and the same domain would block when accessing their session storage area until the first script has executed to completion.) Another (potentially more efficient but probably more complex) implementation strategy is to use optimistic transactional script execution. This specification does not require any particular implementation strategy, so long as the requirement above is met.
A third-party advertiser (or any entity capable of getting content distributed to multiple sites) could use a unique identifier stored in its domain's global storage area to track a user across multiple sessions, building a profile of the user's interests to allow for highly targetted advertising. In conjunction with a site that is aware of the user's real identity (for example an e-commerce site that requires authenticated credentials), this could allow oppressive groups to target individuals with greater accuracy than in a world with purely anonymous Web usage.
The globalStorage
object also introduces a way for sites to cooperate to track users over multiple domains, by storing identifying data in "public" top-level domain storage area, accessible by any domain.
There are a number of techniques that can be used to mitigate the risk of user tracking:
Blocking third-party storage: user agents may restrict access to the globalStorage
object to scripts originating at the domain of the top-level document of the browsing context.
This blocks a third-party site from using its private storage area for tracking a user, but top-level sites could still cooperate with third parties to perferm user tracking by using the "public" storage area.
Expiring stored data: user agents may automatically delete stored data after a period of time.
For example, a user agent could treat the global storage area as session-only storage, deleting the data once the user had closed all the browsing contexts that could access it.
This can restrict the ability of a site to track a user, as the site would then only be able to track the user across multiple sessions when he authenticates with the site itself (e.g. by making a purchase or logging in to a service).
Blocking access to the top-level domain ("public") storage areas: user agents may prevent domains from storing data in and reading data from the top-level domain entries in the globalStorage
object.
In practice this requires a detailed list of all the "public" second-level (and third-level) domains. For example, content at the domain www.example.com
would be allowed to access example.com
data but not com
data; content at the domain example.co.uk
would be allowed access to example.co.uk
but not co.uk
or uk
; and content at example.chiyoda.tokyo.jp
would be allowed access to example.chiyoda.tokyo.jp
but not chiyoda.tokyo.jp
, tokyo.jp
, or jp
, while content at example.metro.tokyo.jp
would be allowed access to both example.metro.tokyo.jp
and metro.tokyo.jp
but not tokyo.jp
or jp
. The problem is even more convoluted when one considers private domains with third-party subdomains such as dyndns.org
or uk.com
.
Blocking access to the "public" storage areas can also prevent innocent sites from cooperating to provide services beneficial to the user.
Treating persistent storage as cookies: user agents may present the persistent storage feature to the user in a way that does not distinguish it from HTTP session cookies. [RFC2965]
This might encourage users to view persistent storage with healthy suspicion.
Site-specific white-listing of access to "public" storage area: user agents may allow sites to access persistent storage for their own domain and subdomains in an unrestricted manner, but require the user to authorise access to the storage area of higher-level domains.
For example, code at example.com
would be always allowed to read and write data for www.example.com
and example.com
, but if it tried to access com
, the user agent could display a non-modal message informing the user that the page requested access to com
and offering to allow it.
Origin-tracking of persistent storage data: user agents may record the domain of the script that caused data to be stored.
If this information is then used to present the view of data currently in persistent storage, it would allow the user to make informed decisions about which parts of the persistent storage to prune. Combined with a blacklist ("delete this data and prevent this domain from ever storing data again"), the user can restrict the use of persistent storage to sites that he trusts.
Shared blacklists: user agents may allow users to share their persistent storage domain blacklists.
This would allow communities to act together to protect their privacy.
While these suggestions prevent trivial use of this API for user tracking, they do not block it altogether. Within a single domain, a site can continue to track the user across multiple sessions, and can then pass all this information to the third party along with any identifying information (names, credit card numbers, addresses) obtained by the site. If a third party cooperates with multiple sites to obtain such information, a profile can still be created.
However, user tracking is to some extent possible even with no cooperation from the user agent whatsoever, for instance by using session identifiers in URIs, a technique already commonly used for innocuous purposes but easily repurposed for user tracking (even retroactively). This information can then be shared with other sites, using using visitors' IP addresses and other user-specific data (e.g. user-agent headers and configuration settings) to combine separate sessions into coherent user profiles.
If the user interface for persistent storage presents data in the persistent storage feature separately from data in HTTP session cookies, then users are likely to delete data in one and not the other. This would allow sites to use the two features as redundant backup for each other, defeating a user's attempts to protect his privacy.
Since the "public" global storage areas are accessible by content from many different parties, it is possible for third-party sites to delete or change information stored in those areas in ways that the originating sites may not expect.
Authors must not use the "public" global storage areas for storing sensitive data. Authors must not trust information stored in "public" global storage areas.
This API makes no distinction between content served over HTTP, FTP, or other host-based protocols, and does not distinguish between content served from different ports at the same host.
Thus, for example, data stored in the global persistent storage for domain "www.example.com" by a page served from HTTP port 80 will be available to a page served in http://example.com:18080/
, even if the latter is an experimental server under the control of a different user.
Since the data is not sent over the wire by the user agent, this is not a security risk in its own right. However, authors must take proper steps to ensure that all hosts that have fully qualified host names that are subsets of hosts dealing with sensitive information are as secure as the originating hosts themselves.
Similarly, authors must ensure that all Web servers on a host, regardless of the port, are equally trusted if any of them are to use persistent storage. For instance, if a Web server runs a production service that makes use of the persistent storage feature, then other users that have access to that machine and that can run a Web server on another port will be able to access the persistent storage added by the production service (assuming they can trick a user into visiting their page).
However, if one is able to trick users into visiting a Web server with the same host name but on a different port as a production service used by these users, then one could just as easily fake the look of the site and thus trick users into authenticating with the fake site directly, forwarding the request to the real site and stealing the credentials in the process. Thus, the persistent storage feature is considered to only minimally increase the risk involved.
Because of the potential for DNS spoofing attacks, one cannot guarentee that a host claiming to be in a certain domain really is from that domain. The secure
attribute is provided to mark certain key/value pairs as only being accessible to pages that have been authenticated using secure certificates (or similar mechanisms).
Authors must ensure that they do not mark sensitive items as "safe for both secure and insecure content". (To prevent the risk of a race condition, data stored by scripts in secure contexts default to being marked as "safe only for secure content".)
Different authors sharing one host name, for example users hosting content on geocities.com
, all share one persistent storage object. There is no feature to restrict the access by pathname. Authors on shared hosts are therefore recommended to avoid using the persistent storage feature, as it would be trivial for other authors to read from and write to the same storage area.
Even if a path-restriction feature was made available, the usual DOM scripting security model would make it trivial to bypass this protection and access the data from any path.
If a "public" global storage area corresponds to a host, as it typically does if for private domains with third-party subdomains such as dyndns.org or uk.com, the host corresponding to the "public" domain has access to all the storage areas of its third-party subdomains. In general, authors are discouraged from using the globalStorage
API for sensitive data unless the operators of all the domains involved are trusted.
User agents may mitigate this problem by preventing hosts corresponding to "public" global storage areas from accessing any storage areas other than their own.
Authors should not store sensitive data using the global storage APIs if there are hosts with fully-qualified domain names that are subsets of their own which they do not trust. For example, an author at finance.members.example.net
should not store sensitive financial user data in the finance.members.example.net
storage area if he does not trust the host that runs example.net
.
If an author publishing content on one host, e.g. example.com
, wishes to use the globalStorage
API but does not wish any content on the host's subdomains to access the data, the author should use an otherwise non-existent subdomain name, e.g., private.example.com
, to store the data. This will be accessible only to that host (and its parent domains), and not to any of the real subdomains (e.g. upload.example.com
).
The two primary risks when implementing this persistent storage feature are letting hostile sites read information from other domains, and letting hostile sites write information that is then read from other domains.
Letting third-party sites read data that is not supposed to be read from their domain causes information leakage, For example, a user's shopping wishlist on one domain could be used by another domain for targetted advertising; or a user's work-in-progress confidential documents stored by a word-processing site could be examined by the site of a competing company.
Letting third-party sites write data to the storage areas of other domains can result in information spoofing, which is equally dangerous. For example, a hostile site could add items to a user's wishlist; or a hostile site could set a user's session identifier to a known ID that the hostile site can then use to track the user's actions on the victim site.
A risk is also presented by servers on local domains having host names matching top-level domain names, for instance having a host called "com" or "net". Such hosts might, if implementations fail to correctly implement the .localdomain
suffixing, have full access to all the data stored in a UA's persistent storage for that top level domain.
Thus, strictly following the model described in this specification is important for user security.
In addition, a number of optional restrictions related to the "public" global storage areas are suggested in the previous sections. The design of this API is intended to be such that not supporting these restrictions, or supporting them less than perfectly, does not result in critical security problems. However, implementations are still encouraged to create and maintain a list of "public" domains, and apply the restrictions described above.
The Audio
interface allows scripts to play sound clips. This interface is intended for sound effects, not for streaming audio or multimedia; for the latter, the object
element is more appropriate. We need to add an API for object to support pausing, etc, of streaming APIs.
There is no markup element that corresponds to Audio
objects, they are only accessible from script.
User agents should allow users to dynamically enable and disable sound output, but doing so must not affect how Audio
objects act in any way other than whether sounds are physically played back or not. For instance, sound files must still be downloaded, load
and error
events must still fire, and if two identical clips are started with a two second interval then when the sound is reenabled they must still be two seconds out of sync.
When multiple sounds are played simultaneously, the user agent must mix the sounds together.
interface Audio { attribute EventListener onload; attribute EventListener onerror; void play(); void loop(); void loop(in unsigned long playCount); void stop();};
Audio
objects must also implement the EventTarget
interface. [DOM3EVENTS]
In ECMAScript, an instance of Audio
can be created using the Audio(uri)
constructor:
var a = new Audio("test.wav");
The Audio()
constructor takes a single argument, a URI (or IRI), which is resolved using the script context's window.location.href
value as the base, and which returns an Audio
object that will, at the completion of the current script, start loading that URI.
Once the URI is loaded, a load
event must be fired on the Audio
object.
Audio
objects have a current position and a play count. Both are initially zero.
The Audio
interface has the following members:
load
event is fired on it. When playback of the sound reaches the end of the available data, its current position is reset to the start of the clip, and the play count is decreased by one (unless it is infinite). If the play count is greater than zero, then the sound is played again.
This section describes various features that allow authors to enable users to edit documents and parts of documents interactively.
This section is non-normative.
Would be nice to explain how these features work together.
contenteditable
attributeThe contenteditable
attribute is a common attribute. User agents must support this attribute on all HTML elements.
redefine this in terms of a microsyntax
If an HTML element has a contenteditable
attribute set to the empty string or the value true
(by case-insensitive match), or if its nearest ancestor with the contenteditable
attribute set has its attribute set to the empty string or the value true
(by case-insensitive match), then the UA must treat the element as editable (as described below).
If an HTML element has a contenteditable
attribute set but the value of the attribute is not the empty string or the literal value true
, or if its nearest ancestor with the contenteditable
attribute set is not editable, or if it has no ancestor with the contenteditable
attribute set, then the element is not editable.
Authors must only use the exact literal values true
and false
with the contenteditable
attribute.
The contentEditable
DOM attribute...
If an element is editable and its parent element is not, then the element is an editing host. Editable elements can be nested. User agents must make editing hosts focusable (which typicially means they enter the tab order). An editing host can contain non-editable sections, these are handled as described below. An editing host can contain non-editable sections that contain further editing hosts.
When an editing host has focus, it must have a caret position that specifies where the current editing position is. It may also have a selection.
How the caret and selection are represented depends entirely on the UA.
There are several actions that the user agent should allow the user to perform while the user is interacting with an editing host. How exactly each action is triggered is not defined for every action, but when it is not defined, suggested key bindings are provided to guide implementors.
User agents must allow users to move the caret to any position within an editing host, even into nested editable elements. This could be triggered as the default action of keydown
events with various key identifiers and as the default action of mouseydown
events.
User agents must allow users to change the selection within an editing host, even into nested editable elements. This could be triggered as the default action of keydown
events with various key identifiers and as the default action of mouseydown
events.
This action must be triggered as the default action of a textInput
event, and may be triggered by other commands as well. It must cause the user agent to insert the specified text (given by the event object's data
attribute in the case of the textInput
event) at the caret.
If the caret is positioned somewhere where inline-level content is not allowed (e.g. because the element accepts "both block-level and inline-level content but not both", and the element already contains block-level content), then the user agent must not insert the text directly at the caret position. In such cases the behaviour is UA-dependent, but user agents must not, in response to a request to insert text, generate a DOM that is less conformant than the DOM prior to the request.
User agents should allow users to insert new paragraphs into elements that only contain block-level content.
For example, given the markup:
AMPERSANDlt;sectionAMPERSANDgt; AMPERSANDlt;dlAMPERSANDgt; AMPERSANDlt;dtAMPERSANDgt; Ben AMPERSANDlt;/dtAMPERSANDgt; AMPERSANDlt;ddAMPERSANDgt; Goat AMPERSANDlt;/ddAMPERSANDgt; AMPERSANDlt;/dlAMPERSANDgt;AMPERSANDlt;/sectionAMPERSANDgt;
...the user agent should allow the user to insert p
elements before and after the dl
element, as children of the section
element.
UAs should offer a way for the user to request that the current block be broken at the caret, e.g. as the default action of a keydown
event whose identifier is the "Enter" key and that has no modifiers set.
The exact behaviour is UA-dependent, but user agents must not, in response to a request to break a block, generate a DOM that is less conformant than the DOM prior to the request.
UAs should offer a way for the user to request an explicit line break at the caret position without breaking the block, for example as in a poem verse or an address. To insert a line break, the user agent must insert a br
element.
If the caret is positioned somewhere where inline-level content is not allowed (e.g. because the element accepts "both block-level and inline-level content but not both", and the element already contains block-level content), then the user agent must not insert the br
element directly at the caret position. In such cases the behaviour is UA-dependent, but user agents must not, in response to a request to insert a line separator, generate a DOM that is less conformant than the DOM prior to the request.
UAs should offer a way for the user to delete text and elements, e.g. as the default action of keydown
events whose identifiers are "U+0008" or "U+007F".
Five edge cases in particular need to be considered carefully when implementing this feature: backspacing at the start of an element, backspacing when the caret is immediately after an element, forward-deleting at the end of an element, forward-deleting when the caret is immediately before an element, and deleting a selection whose start and end points do not share a common parent node.
In any case, the exact behaviour is UA-dependent, but user agents must not, in response to a request to delete text or an element, generate a DOM that is less conformant than the DOM prior to the request.
UAs should offer a way for the user to mark text as having stress emphasis and as being important, and may offer the user the ability to mark text and blocks with other semantics.
UAs should similarly offer a way for the user to insert empty semantic elements (such as, again, em
, strong
, and others) to subsequently fill by entering text manually.
UAs should also offer a way to remove those semantics from marked up text, and to remove empty semantic element that have been inserted.
The exact behaviour is UA-dependent, but user agents must not, in response to a request to wrap semantics around some text or to insert or remove a semantic element, generate a DOM that is less conformant than the DOM prior to the request.
UAs should offer a way for the user to move images and other non-editable parts around the content within an editing host. This may be done using the drag and drop mechanism. User agents must not, in response to a request to move non-editable elements nested inside editing hosts, generate a DOM that is less conformant than the DOM prior to the request.
When an editable form control is edited, the changes must be reflected in both its current value and its default value. For input
elements this means updating the defaultValue
DOM attribute as well as the value
DOM attribute; for select
elements it means updating the option
elements' defaultSelected
DOM attribute as well as the selected
DOM attribute; for textarea
elements this means updating the defaultValue
DOM attribute as well as the value
DOM attribute. (Updating the default*
DOM attributes causes content attributs to be updated as well.)
User agents may perform several commands per user request; for example if the user selects a block of text and hits Enter, the UA might interpret that as a request to delete the content of the selection followed by a request to break the block at that position.
This section will define document.designMode
.
This section defines an event-based drag-and-drop mechanism.
This specification does not define exactly what a drag and drop operation actually is.
On a visual medium with a pointing device, a drag operation could be the default action of a mousedown
event that is followed by a series of mousemove
events, and the drop could be triggered by the mouse being released.
On media without a pointing device, the user would probably have to explicitly indicate his intention to perform a drag-and-drop operation, stating what he wishes to drag and what he wishes to drop, respectively.
However it is implemented, drag and drop operations must have a starting point (e.g. where the mouse was clicked, or the start of the selection or element that was selected for the drag), may have any number of intermediate steps (elements that the mouse moves over during a drag, or elements that the user picks as possible drop points as he cycles through possibilities), and must either have an end point (the element above which the mouse button was released, or the element that was finally selected), or be canceled. The end point must be the last element selected as a possible drop point before the drop occurs (so if the operation is not canceled, there must be at least one element in the middle step).
DragEvent
and DataTransfer
interfacesThe drag-and-drop processing model involves several events. They all use the DragEvent
interface.
interface DragEvent : Event { readonly attribute DataTransfer dataTransfer; void initDragEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg); void initDragEventNS(in DOMString namespaceURIArg, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg);};
The initDragEvent()
and initDragEventNS()
methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
The dataTransfer
attribute of the DragEvent
interface represents the context information for the event.
When a DragEvent
object is created, a new DataTransfer
object must be created and assigned to the dataTransfer
context information field of the event object.
interface DataTransfer { attribute DOMString dropEffect; attribute DOMString effectAllowed; void clearData(in DOMString format); void setData(in DOMString format, in DOMString data); DOMString getData(in DOMString format); void setDragImage(in Element image, in long x, in long y); void addElement(in Element element);};
DataTransfer
objects can conceptually contain various kinds of data.
When a DragEvent
event object is initialised, the DataTransfer
object created for the event's dataTransfer
member must be initialised as follows:
DataTransfer
object must initially contain no data, no elements, and have no associated image. DataTransfer
object's effectAllowed
attribute must be set to "uninitialized
". dropEffect
attribute must be set to "none
". The dropEffect
attribute controls the drag and drop feedback that the user is given during a drag and drop operation.
The attribute must ignore any attempts to set it to a value other than none
, copy
, link
, and move
. On getting, the attribute must return the last of those four values that it was set to.
The effectAllowed
attribute is used in the drag and drop processing model to initialise the dropEffect
attribute during the dragenter
and dragover
events.
The attribute must ignore any attempts to set it to a value other than none
, copy
, copyLink
, copyMove
, link
, linkMove
, move
, all
, and uninitialized
. On getting, the attribute must return the last of those values that it was set to.
DataTransfer
objects can hold pieces of data, each associated with a unique format. Formats are generally given by MIME types, with some values special-cased for legacy reasons.
The clearData(format)
method must clear the DataTransfer
object of any data associated with the given format. If format is the value "Text
", then it must be treated as "text/plain
". If the format is "URL
", then it must be treated as "text/uri-list
".
The setData(format, data)
method must add data to the data stored in the DataTransfer
object, labelled as being of the type format. This must replace any previous data that had been set for that format. If format is the value "Text
", then it must be treated as "text/plain
". If the format is "URL
", then it must be treated as "text/uri-list
".
The getData(format)
method must return the data that is associated with the type format, if any, and must return the empty string otherwise. If format is the value "Text
", then it must be treated as "text/plain
". If the format is "URL
", then the data associated with the "text/uri-list
" format must be parsed as appropriate for text/uri-list
data, and the first URI from the list must be returned. If there is no data with that format, or if there is but it has no URIs, then the method must return the empty string. [RFC2483]
The setDragImage(element, x, y)
method sets which element to use to generate the drag feedback. The element argument can be any Element
; if it is an img
element, then the user agent should use the element's image (at its intrinsic size) to generate the feedback, otherwise the user agent should base the feedback on the given element (but the exact mechanism for doing so is not specified).
The addElement(element)
method is an alternative way of specifying how the user agent is to render the drag feedback. It adds an element to the DataTransfer
object.
The following events are involved in the drag-and-drop model. Whenever the processing model described below causes one of these events to be fired, the event fired must use the DragEvent
interface defined above, must have the bubbling and cancelable behaviours given in the table below, and must have the context information set up as described after the table.
Event Name | Target | Bubbles? | Cancelable? | dataTransfer | effectAllowed | dropEffect | Default Action |
---|---|---|---|---|---|---|---|
dragstart | Source node | AMPERSAND#x2713; Bubbles | AMPERSAND#x2713; Cancelable | Contains source node unless a selection is being dragged, in which case it is empty | uninitialized | none | Initiate the drag-and-drop operation |
drag | Source node | AMPERSAND#x2713; Bubbles | AMPERSAND#x2713; Cancelable | Empty | Same as last event | none | Continue the drag-and-drop operation |
dragenter | Immediate user selection or the body element | AMPERSAND#x2713; Bubbles | AMPERSAND#x2713; Cancelable | Empty | Same as last event | Based on effectAllowed value | Reject immediate user selection as potential target element |
dragleave | Previous target element | AMPERSAND#x2713; Bubbles | AMPERSANDmdash; | Empty | Same as last event | none | None |
dragover | Current target element | AMPERSAND#x2713; Bubbles | AMPERSAND#x2713; Cancelable | Empty | Same as last event | Based on effectAllowed value | Reset the current drag operation to "none" |
drop | Current target element | AMPERSAND#x2713; Bubbles | AMPERSAND#x2713; Cancelable | getData() returns data set in dragstart event | Same as last event | Current drag operation | Varies |
dragend | Source node | AMPERSAND#x2713; Bubbles | AMPERSANDmdash; | Empty | Same as last event | Current drag operation | Varies |
The dataTransfer
object's contents are empty except for dragstart
events and drop
events, for which the contents are set as described in the processing model, below.
The effectAllowed
attribute must be set to "uninitialized
" for dragstart
events, and to whatever value the field had after the last drag-and-drop event was fired for all other events (only counting events fired by the user agent for the purposes of the drag-and-drop model described below).
The dropEffect
attribute must be set to "none
" for dragstart
, drag
, dragleave
, and dragend
events (except when stated otherwise in the algorithms given in the sections below), to the value corresponding to the current drag operation for drop
events, and to a value based on the effectAllowed
attribute's value and to the drag-and-drop source, as given by the following table, for the remaining events (dragenter
and dragover
):
effectAllowed | dropEffect |
---|---|
none | none |
copy , copyLink , copyMove , all | copy |
link , linkMove | link |
move | move |
uninitialized when what is being dragged is a selection from a text field | move |
uninitialized when what is being dragged is a selection | copy |
uninitialized when what is being dragged is an a element with an href attribute | link |
Any other case | copy |
When the user attempts to begin a drag operation, the user agent must first determine what is being dragged. If the drag operation was invoked on a selection, then it is the selection that is being dragged. Otherwise, it is the first element, going up the ancestor chain, starting at the node that the user tried to drag, that has the DOM attribute draggable
set to true. If there is no such element, then nothing is being dragged, the drag-and-drop operation is never started, and the user agent must not continue with this algorithm.
img
elements and a
elements with an href
attribute have their draggable
attribute set to true by default.
If the user agent determines that something can be dragged, a dragstart
event must then be fired.
If it is a selection that is being dragged, then this event must be fired on the node that the user started the drag on (typically the text node that the user originally clicked). If the user did not specify a particular node, for example if the user just told the user agent to begin a drag of "the selection", then the event must be fired on the deepest node that is a common ancestor of all parts of the selection.
If it is not a selection that is being dragged, then the event must be fired on the element that is being dragged.
The node on which the event is fired is the source node. Multiple events are fired on this node during the course of the drag-and-drop operation.
If it is a selection that is being dragged, the dataTransfer
member of the event must be created with no nodes. Otherwise, it must be created containing just the source node. Script can use the addElement()
method to add further elements to the list of what is being dragged.
If it is a selection that is being dragged, the dataTransfer
member of the event must have the text of the selection added to it as the data associated with the text/plain
format. Otherwise, if it is an img
element being dragged, then the value of the element's src
DOM attribute must be added, associated with the text/uri-list
format. Otherwise, if it is an a
element being dragged, then the value of the element's href
DOM attribute must be added, associated with the text/uri-list
format. Otherwise, no data is added to the object by the user agent.
If the event is canceled, then the drag and drop operation must not occur; the user agent must not continue with this algorithm.
If it is not canceled, then the drag and drop operation must be initiated.
Since events with no event handlers registered are, almost by definition, never canceled, drag and drop is always available to the user if the author does not specifically prevent it.
The drag-and-drop feedback must be generated from the first of the following sources that is available:
setDragImage()
method of the dataTransfer
object of the dragstart
event, if the method was called. In visual media, if this is used, the x and y arguments that were passed to that method should be used as hints for where to put the cursor relative to the resulting image. The values are expressed as distances in CSS pixels from the left side and from the top side of the image respectively. [CSS21]dataTransfer
object, both before the event was fired, and during the handling of the event using the addElement()
method, if any such elements were indeed added. The user agent must take a note of the data that was placed in the dataTransfer
object. This data will be made available again when the drop
event is fired.
From this point until the end of the drag-and-drop operation, device input events (e.g. mouse and keyboard events) must be suppressed. In addition, the user agent must track all DOM changes made during the drag-and-drop operation, and add them to its undo history as one atomic operation once the drag-and-drop operation has ended.
During the drag operation, the element directly indicated by the user as the drop target is called the immediate user selection. (Only elements can be selected by the user; other nodes must not be made available as drop targets.) However, the immediate user selection is not necessarily the current target element, which is the element currently selected for the drop part of the drag-and-drop operation. The immediate user selection changes as the user selects different elements (either by pointing at them with a pointing device, or by selecting them in some other way). The current target element changes when the immediate user selection changes, based on the results of event handlers in the document, as described below.
Both the current target element and the immediate user selection can be null, which means no target element is selected. They can also both be elements in other (DOM-based) documents, or other (non-Web) programs altogether. (For example, a user could drag text to a word-processor.) The current target element is initially null.
In addition, there is also a current drag operation, which can take on the values "none", "copy", "link", and "move". Initially it has the value "none". It is updated by the user agent as described in the steps below.
User agents must, every 350ms (AMPERSAND#xB1;200ms), perform the following steps in sequence. (If the user agent is still performing the previous iteration of the sequence when the next iteration becomes due, the user agent must not execute the overdue iteration, effectively "skipping missed frames" of the drag and drop operation.)
First, the user agent must fire a drag
event at the source node. If this event is canceled, the user agent must set the current drag operation to none (no drag operation).
Next, if the drag
event was not canceled and the user has not ended the drag-and-drop operation, the user agent must check the state of the drag-and-drop operation, as follows:
First, if the user is indicating a different immediate user selection than during the last iteration (or if this is the first iteration), and if this immediate user selection is not the same as the current target element, then the current target element must be updated, as follows:
If the new immediate user selection is null, or is in a non-DOM document or application, then set the current target element to the same value.
Otherwise, the user agent must fire a dragenter
event at the immediate user selection.
If the event is canceled, then the current target element must be set to the immediate user selection.
Otherwise, if the current target element is not the body element, the user agent must fire a dragenter
event at the body element, and the current target element must be set to the body element, regardless of whether that event was canceled or not. (If the body element is null, then the current target element would be set to null too in this case, it wouldn't be set to the Document
object.)
If the previous step caused the current target element to change, and if the previous target element was not null or a part of a non-DOM document, the user agent must fire a dragleave
event at the previous target element.
If the current target element is a DOM element, the user agent must fire a dragover
event at this current target element.
If the dragover
event is canceled, the current drag operation must be reset to "none".
Otherwise, the current drag operation must be set based on the values the effectAllowed
and dropEffect
attributes of the dataTransfer
object had after the event was handled, as per the following table:
effectAllowed | dropEffect | Drag operation |
---|---|---|
uninitialized , copy , copyLink , copyMove , or all | copy | "copy" |
uninitialized , link , copyLink , linkMove , or all | link | "link" |
uninitialized , move , copyMove , linkMove , or all | move | "move" |
Any other case | "none" |
Then, regardless of whether the dragover
event was canceled or not, the drag feedback (e.g. the mouse cursor) must be updated to match the current drag operation, as follows:
Drag operation | Feedback |
---|---|
"copy" | Data will be copied if dropped here. |
"link" | Data will be linked if dropped here. |
"move" | Data will be moved if dropped here. |
"none" | No operation allowed, dropping here will cancel the drag and drop operation. |
Otherwise, if the current target element is not a DOM element, the user agent must use platform-specific mechanisms to determine what drag operation is being performed (none, copy, link, or move). This sets the current drag operation.
Otherwise, if the user ended the drag and drop operation (e.g. by releasing the mouse button in a mouse-driven drag-and-drop interface), or if the drag
event was cancelled, then this will be the last iteration. The user agent must follow the following steps, then stop looping.
If the current drag operation is none (no drag operation), or, if the user ended the drag-and-drop operation by canceling it (e.g. by hitting the Escape key), or if the current target element is null, then the drag operation failed. If the current target element is a DOM element, the user agent must fire a dragleave
event at it; otherwise, if it is not null, it must use platform-specific conventions for drag cancellation.
Otherwise, the drag operation was as success. If the current target element is a DOM element, the user agent must fire a drop
event at it; otherwise, it must use platform-specific conventions for indicating a drop.
When the target is a DOM element, the dropEffect
attribute of the event's dataTransfer
object must be given the value representing the current drag operation (copy
, link
, or move
), and the object must be set up so that the getData()
method will return the data that was added during the dragstart
event.
If the event is canceled, the current drag operation must be set to the value of the dropEffect
attribute of the event's dataTransfer
object as it stood after the event was handled.
Otherwise, the event is not canceled, and the user agent must perform the event's default action, which depends on the exact target as follows:
textarea
, or an input
element with type="text"
) text/plain
format, if any, into the text field in a manner consistent with platform-specific conventions (e.g. inserting it at the current mouse cursor position, or inserting it at the end of the field). Finally, the user agent must fire a dragend
event at the source node, with the dropEffect
attribute of the event's dataTransfer
object being set to the value corresponding to the current drag operation.
The current drag operation can change during the processing of the drop
event, if one was fired.
The event is not cancelable. After the event has been handled, the user agent must act as follows:
textarea
, or an input
element with type="text"
), and a drop
event was fired in the previous step, and the current drag operation is "move", and the source of the drag and drop operation is a selection in the DOM textarea
, or an input
element with type="text"
), and a drop
event was fired in the previous step, and the current drag operation is "move", and the source of the drag and drop operation is a selection in a text field The model described above is independent of which Document
object the nodes involved are from; the events must be fired as described above and the rest of the processing model must be followed as described above, irrespective of how many documents are involved in the operation.
If the drag is initiated in another application, the source node is not a DOM node, and the user agent must use platform-specific conventions instead when the requirements above involve the source node. User agents in this situation must act as if the dragged data had been added to the DataTransfer
object when the drag started, even though no dragstart
event was actually fired; user agents must similarly use platform-specific conventions when deciding on what drag feedback to use.
If a drag is started in a document but ends in another application, then the user agent must instead replace the parts of the processing model relating to handling the target according to platform-specific conventions.
In any case, scripts running in the context of the document must not be able to distinguish the case of a drag-and-drop operation being started or ended in another application from the case of a drag-and-drop operation being started or ended in another document from another domain.
draggable
attributeAll elements may have the draggable
content attribute set. If the attribute is set, it must be set either to the empty string, to the value true
, or to the value false
.
redefine this in terms of a microsyntax
The draggable
DOM attribute, whose value depends on the content attribute's in the way described below, controls whether or not the element is draggable. Generally, only text selections are draggable, but elements whose draggable
DOM attribute is true become draggable as well.
If an element has the draggable
content attribute set to the empty string or to the literal value true
, the draggable
DOM attribute must return true.
Otherwise, if an element has the draggable
content attribute set to the literal value false
, the draggable
DOM attribute must return false.
Otherwise, if the element is an img
element, or, if the element is an a
element with an href
content attribute, the draggable
DOM attribute must return true.
Otherwise, the draggable
DOM must return false.
If the draggable
DOM attribute is set to the value false, the draggable
content attribute must be set to the literal value false
. If the draggable
DOM attribute is set to the value true, the draggable
content attribute must be set to the literal value true
.
User agents must not make the data added to the DataTransfer
object during the dragstart
event available to scripts until the drop
event, because otherwise, if a user were to drag sensitive information from one document to a second document, crossing a hostile third document in the process, the hostile document could intercept the data.
For the same reason, user agents must only consider a drop to be successful if the user specifically ended the drag operation AMPERSANDmdash; if any scripts end the drag operation, it must be considered unsuccessful (canceled) and the drop
event must not be fired.
User agents should take care to not start drag and drop operations in response to script actions. For example, in a mouse-and-window environment, if a script moves a window while the user has his mouse button depressed, the UA would not consider that to start a drag. This is important because otherwise UAs could cause data to be dragged from sensitive sources and dropped into hostile documents without the user's consent.
There has got to be a better way of doing this, surely.
The user agent must associate an undo transaction history with each HTMLDocument
object.
The undo transaction history is a list of entries. The entries are of two type: DOM changes and undo objects.
Each DOM changes entry in the undo transaction history consists of batches of one or more of the following:
Element
node. Node
.HTMLDocument
object (parentNode
, childNodes
). Undo object entries consist of objects representing state that scripts running in the document are managing. For example, a Web mail application could use an undo object to keep track of the fact that a user has moved an e-mail to a particular folder, so that the user can undo the action and have the e-mail return to its former location.
Broadly speaking, DOM changes entries are handled by the UA in response to user edits of form controls and editing hosts on the page, and undo object entries are handled by script in response to higher-level user actions (such as interactions with server-side state, or in the implementation of a drawing tool).
UndoManager
interfaceThis API sucks. Seriously. It's a terrible API. Really bad. I hate it. Here are the requirements:
To manage undo object entries in the undo transaction history, the UndoManager
interface can be used:
interface UndoManager { unsigned long add(in DOMObject data, in DOMStrong title); void remove(in unsigned long index); void clearUndo(); void clearRedo(); DOMObject item(in unsigned long index); readonly attribute unsigned long length; readonly attribute unsigned long position;};
The undoManager
attribute of the WindowHTML
interface must return the object implementing the UndoManager
interface for that WindowHTML
object's associated HTMLDocument
object.
In the ECMAScript DOM binding, objects implementing this interface must also support being dereferenced using the square bracket notation, such that dereferencing with an integer index is equivalent to invoking the item()
method with that index (e.g. undoManager[1]
returns the same as undoManager.item(1)
).
UndoManager
objects represent their document's undo transaction history. Only undo object entries are visible with this API, but this does not mean that DOM changes entries are absent from the undo transaction history.
The length
attribute must return the number of undo object entries in the undo transaction history.
The item(n)
method must return the nth undo object entry in the undo transaction history.
The undo transaction history has a current position. This is the position between two entries in the undo transaction history's list where the previous entry represents what needs to happen if the user invokes the "undo" command (the "undo" side, lower numbers), and the next entry represents what needs to happen if the user invokes the "redo" command (the "redo" side, higher numbers).
The position
attribute must return the index of the undo object entry nearest to the undo position, on the "redo" side. If there are no undo object entries on the "redo" side, then the attribute must return the same as the length
attribute. If there are no undo object entries on the "undo" side of the undo position, the position
attribute returns zero.
Since the undo transaction history contains both undo object entries and DOM changes entries, but the position
attribute only returns indices relative to undo object entries, it is possible for several "undo" or "redo" actions to be performed without the value of the position
attribute changing.
The add(data, title)
method's behaviour depends on the current state. Normally, it must insert the data object passed as an argument into the undo transaction history immediately before the undo position, optionally remembering the given title to use in the UI. If the method is called during an undo operation, however, the object must instead be added immediately after the undo position.
If the method is called and there is neither an undo operation in progress nor a redo operation in progress then any entries in the undo transaction history after the undo position must be removed (as if clearRedo()
had been called).
We could fire events when someone adds something to the undo history -- one event per undo object entry before the position (or after, during redo addition), allowing the script to decide if that entry should remain or not. Or something. Would make it potentially easier to expire server-held state when the server limitations come into play.
The remove(index)
method must remove the undo object entry with the specified index. If the index is less than zero or greater than or equal to length
then the method must raise an INDEX_SIZE_ERR
exception. DOM changes entries are unaffected by this method.
The clearUndo()
method must remove all entries in the undo transaction history before the undo position, be they DOM changes entries or undo object entries.
The clearRedo()
method must remove all entries in the undo transaction history after the undo position, be they DOM changes entries or undo object entries.
Another idea is to have a way for scripts to say "startBatchingDOMChangesForUndo()" and after that the changes to the DOM go in as if the user had done them.
When the user invokes an undo operation, or when the execCommand()
method is called with the undo
command, the user agent must perform an undo operation.
If the undo position is at the start of the undo transaction history, then the user agent must do nothing.
If the entry immediately before the undo position is a DOM changes entry, then the user agent must remove that DOM changes entry, reverse the DOM changes that were listed in that entry, and, if the changes were reversed with no problems, add a new DOM changes entry (consisting of the opposite of those DOM changes) to the undo transaction history on the other side of the undo position.
If the DOM changes cannot be undone (e.g. because the DOM state is no longer consistent with the changes represented in the entry), then the user agent must simply remove the DOM changes entry, without doing anything else.
If the entry immediately before the undo position is an undo object entry, then the user agent must first remove that undo object entry from the undo transaction history, and then must fire an undo
event on the Document
object, using the undo object entry's associated undo object as the event's data.
Any calls to add()
while the event is being handled will be used to populate the redo history, and will then be used if the user invokes the "redo" command to undo his undo.
When the user invokes a redo operation, or when the execCommand()
method is called with the redo
command, the user agent must perform a redo operation.
This is mostly the opposite of an undo operation, but the full definition is included here for completeness.
If the undo position is at the end of the undo transaction history, then the user agent must do nothing.
If the entry immediately after the undo position is a DOM changes entry, then the user agent must remove that DOM changes entry, reverse the DOM changes that were listed in that entry, and, if the changes were reversed with no problems, add a new DOM changes entry (consisting of the opposite of those DOM changes) to the undo transaction history on the other side of the undo position.
If the DOM changes cannot be redone (e.g. because the DOM state is no longer consistent with the changes represented in the entry), then the user agent must simply remove the DOM changes entry, without doing anything else.
If the entry immediately after the undo position is an undo object entry, then the user agent must first remove that undo object entry from the undo transaction history, and then must fire a redo
event on the Document
object, using the undo object entry's associated undo object as the event's data.
UndoManagerEvent
interface and the undo
and redo
eventsinterface UndoManagerEvent : Event { readonly attribute DOMObject data; void initUndoManagerEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMObject dataArg); void initUndoManagerEventNS(in DOMString namespaceURIArg, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMObject dataArg);};
The initUndoManagerEvent()
and initUndoManagerEventNS()
methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
The data
attribute represents the undo object for the event.
The undo
and redo
events do not bubble, cannot be canceled, and have no default action. When the user agent fires one of these events it must use the UndoManagerEvent
interface, with the data
field containing the relevant undo object.
How user agents present the above conceptual model to the user is not defined. The undo interface could be a filtered view of the undo transaction history, it could manipulate the undo transaction history in ways not described above, and so forth. For example, it is possible to design a UA that appears to have separate undo transaction histories for each form control; similarly, it is possible to design systems where the user has access to more undo information than is present in the offical (as described above) undo transaction history (such as providing a tree-based approach to document state). Such UI models should be based upon the single undo transaction history described in this section, however, such that to a script there is no detectable difference.
The execCommand(commandID, doShowUI, value)
method on the HTMLDocument
interface allows scripts to perform actions on the current selection or at the current caret position. Generally, these commands would be used to implement editor UI, for example having a "delete" button on a toolbar.
There are three variants to this method, with one, two, and three arguments respectively. The doShowUI and value parameters, even if specified, are ignored unless otherwise stated.
In this specification, in fact, the doShowUI parameter is always ignored, regardless of its value. It is included for historical reasons only.
When any of these methods are invoked, user agents must act as described in the list below.
For actions marked "editing hosts only", if the selection is not entirely within an editing host, of if there is no selection and the caret is not inside an editing host, then the user agent must do nothing.
undo
redo
selectAll
unselect
The user agent must change the selection so that nothing is selected.
We need some sort of way in which the user can make a selection without risk of script clobbering it.
superscript
sup
element (or unwrapped, or, if there is no selection, have that semantic inserted or removed AMPERSANDmdash; the exact behaviour is UA-defined). subscript
sub
element (or, again, unwrapped, or have that semantic inserted or removed, as defined by the UA). formatBlock
Editing hosts only. This command changes the semantics of the blocks containing the selection.
If there is no selection, then, where in the description below refers to the selection, the user agent must act as if the selection was an empty range at the caret position.
If the value parameter is not specified or has a value other than one of the following literal strings:
AMPERSANDlt;addressAMPERSANDgt;
AMPERSANDlt;asideAMPERSANDgt;
AMPERSANDlt;h1AMPERSANDgt;
AMPERSANDlt;h2AMPERSANDgt;
AMPERSANDlt;h3AMPERSANDgt;
AMPERSANDlt;h4AMPERSANDgt;
AMPERSANDlt;h5AMPERSANDgt;
AMPERSANDlt;h6AMPERSANDgt;
AMPERSANDlt;navAMPERSANDgt;
AMPERSANDlt;pAMPERSANDgt;
AMPERSANDlt;preAMPERSANDgt;
...then the user agent must do nothing.
Otherwise, the user agent must, for every position in the selection, take the furthest block-level element ancestor of that position that contains only inline-level content and is not being used as a structured inline-level element, and, if that element is a descendant of the editing host, rename it according to the value, by stripping the leading AMPERSANDlt;
character and the trailing AMPERSANDgt;
character and using the rest as the new tag name.
delete
forwardDelete
insertLineBreak
insertParagraph
insertText
vendorID-customCommandID
vendorID-customCommandID
so as to prevent clashes between extensions from different vendors and future additions to this specification. Every browsing context has a selection. The selection may be empty, and the selection may have more than one range (a disjointed selection). The user should be able to change the selection. User agents are not required to let the user select more than one range, and may collapse multiple ranges in the selection to a single range when the user interacts with the selection. (But, of course, the user agent may let the user create selections with multiple ranges.)
This one selection must be shared by all the content of the browsing context (though not by nested browsing contexts), including any editing hosts in the document. (Editing hosts that are not inside a document cannot have a selection.)
If the selection is empty (collapsed, so that it has only one segment and that segment's start and end points are the same) then the selection's position should equal the caret position. When the selection is not empty, this specification does not define the caret position; user agents should follow platform conventions in deciding whether the caret is at the start of the selection, the end of the selection, or somewhere else.
On some platforms (such as those using Wordstar editing conventions), the caret position is totally independent of the start and end of the selection, even when the selection is empty. On such platforms, user agents may ignore the requirement that the cursor position be linked to the position of the selection altogether.
Mostly for historical reasons, in addition to the browsing context's selection, each textarea
and input
element has an independent selection. These are the text field selections.
The datagrid
and select
elements also have selections, indicating which items have been picked by the user. These are not discussed in this section.
This specification does not specify how selections are presented to the user. The Selectors specification, in conjunction with CSS, can be used to style text selections using the ::selection
pseudo-element. [SELECTORS] [CSS21]
The getSelection()
method on the WindowHTML
interface must return the Selection
object representing the selection of that WindowHTML
object's browsing context.
For historical reasons, the getSelection()
method on the HTMLDocument
interface must return the same Selection
object.
interface Selection { readonly attribute Node anchorNode; readonly attribute long anchorOffset; readonly attribute Node focusNode; readonly attribute long focusOffset; readonly attribute boolean isCollapsed; void collapse(in Node parentNode, in long offset); void collapseToStart(); void collapseToEnd(); void selectAllChildren(in Node parentNode); void deleteFromDocument(); readonly attribute long rangeCount; Range getRangeAt(in long index); void addRange(in Range range); void removeRange(in Range range); void removeAllRanges(); DOMString toString();};
The Selection
interface is represents a list of Range
objects. The first item in the list has index 0, and the last item has index count-1, where count is the number of ranges in the list. [DOM2RANGE]
All of the members of the Selection
interface are defined in terms of operations on the Range
objects represented by this object. These operations can raise exceptions, as defined for the Range
interface; this can therefore result in the members of the Selection
interface raising exceptions as well, in addition to any explicitly called out below.
The anchorNode
attribute must return the value returned by the startContainer
attribute of the last Range
object in the list, or null if the list is empty.
The anchorOffset
attribute must return the value returned by the startOffset
attribute of the last Range
object in the list, or 0 if the list is empty.
The focusNode
attribute must return the value returned by the endContainer
attribute of the last Range
object in the list, or null if the list is empty.
The focusOffset
attribute must return the value returned by the endOffset
attribute of the last Range
object in the list, or 0 if the list is empty.
The isCollapsed
attribute must return true if there are zero ranges, or if there is exactly one range and its collapsed
attribute is itself true. Otherwise it must return false.
The collapse(parentNode, offset)
method must raise a WRONG_DOCUMENT_ERR
DOM exception if parentNode's ownerDocument
is not the HTMLDocument
object with which the Selection
object is associated. Otherwise it is, and the method must remove all the ranges in the Selection
list, then create a new Range
object, add it to the list, and invoke its setStart()
and setEnd()
methods with the parentNode and offset values as their arguments.
The collapseToStart()
method must raise an INVALID_STATE_ERR
DOM exception if there are no ranges in the list. Otherwise, it must invoke the collapse()
method with the startContainer
and startOffset
values of the first Range
object in the list as the arguments.
The collapseToEnd()
method must raise an INVALID_STATE_ERR
DOM exception if there are no ranges in the list. Otherwise, it must invoke the collapse()
method with the endContainer
and endOffset
values of the last Range
object in the list as the arguments.
The selectAllChildren(parentNode)
method must invoke the collapse()
method with the parentNode value as the first argument and 0 as the second argument, and must then invoke the selectNodeContents()
method on the first (and only) range in the list with the parentNode value as the argument.
The deleteFromDocument()
method must invoke the deleteContents()
method on each range in the list, if any, from first to last.
The rangeCount
attribute must return the number of ranges in the list.
The getRangeAt(index)
method must return the indexth range in the list. If index is less than zero or greater or equal to the value returned by the rangeCount
attribute, then the method must raise an INDEX_SIZE_ERR
DOM exception.
The addRange(range)
method must add the given range Range object to the list of selections, at the end (so the newly added range is the new last range). Duplicates are not prevented; a range may be added more than once in which case it appears in the list more than once, which (for example) will cause toString()
to return the range's text twice.
The removeRange(range)
method must remove the first occurrence of range in the list of ranges, if it appears at all.
The removeAllRanges()
method must remove all the ranges from the list of ranges, such that the rangeCount
attribute returns 0 after the removeAllRanges()
method is invoked (and until a new range is added to the list, either through this interface or via user interaction).
The toString()
method must return a concatenation of the results of invoking the toString()
method of the Range
object on each of the ranges of the selection, in the order they appear in the list (first to last).
In language bindings where this is supported, objects implementing the Selection
interface must stringify to the value returned by the object's toString()
method.
In the following document fragment, the emphasised parts indicate the selection.
AMPERSANDlt;p>The cute girl likes the AMPERSANDlt;cite>Oxford English DictionaryAMPERSANDlt;/cite>.AMPERSANDlt/p>
If a script invoked window.getSelection().toString()
, the return value would be "the Oxford English
".
The Selection
interface has no relation to the DataGridSelection
interface.
When we define HTMLTextAreaElement and HTMLInputElement we will have to add the IDL given below to both of their IDLs.
The input
and textarea
elements define four members in their DOM interfaces for handling their text selection:
void select(); attribute unsigned long selectionStart; attribute unsigned long selectionEnd; void setSelectionRange(in unsigned long start, in unsigned long end);
These methods and attributes expose and control the selection of input
and textarea
text fields.
The select()
method must cause the contents of the text field to be fully selected.
The selectionStart
attribute must, on getting, return the offset (in logical order) to the character that immediately follows the start of the selection. If there is no selection, then it must return the offset (in logical order) to the character that immediately follows the text entry cursor.
On setting, it must act as if the setSelectionRange()
method had been called, with the new value as the first argument, and the current value of the selectionEnd
attribute as the second argument, unless the current value of the selectionEnd
is less than the new value, in which case the second argument must also be the new value.
The selectionEnd
attribute must, on getting, return the offset (in logical order) to the character that immediately follows the end of the selection. If there is no selection, then it must return the offset (in logical order) to the character that immediately follows the text entry cursor.
On setting, it must act as if the setSelectionRange()
method had been called, with the current value of the selectionStart
attribute as the first argument, and new value as the second argument.
The setSelectionRange(start, end)
method must set the selection of the text field to the sequence of characters starting with the character at the startth position (in logical order) and ending with the character at the (end-1)th position. Arguments greater than the length of the value in the text field must be treated as pointing at the end of the text field. If end is less than or equal to start then the start of the selection and the end of the selection must both be placed immediately before the character with offset end. In UAs where there is no concept of an empty selection, this must set the cursor to be just before the character with offset end.
To obtain the currently selected text, the following JavaScript suffices:
var selectionText = control.value.substring(control.selectionStart, control.selectionEnd);
...where control is the input
or textarea
element.
Characters with no visible rendering, such as U+200D ZERO WIDTH JOINER, still count as characters. Thus, for instance, the selection can include just an invisible character, and the text insertion cursor can be placed to one side or another of such a character.
When these methods and attributes are used with input
elements that are not displaying simple text fields, they must raise an INVALID_STATE_ERR
exception.
This section describes a mechanism for allowing servers to dispatch DOM events into documents that expect it.
event-source
elementTo specify an event source in an HTML document authors use a new (empty) element event-source
, with an attribute src=""
that takes a URI (or IRI) to open as a stream and, if the data found at that URI is of the appropriate type, treat as an event source.
The event-source
element may also have an onevent=""
attribute. If present, the attribute must be treated as script representing an event handler registered as non-capture listener of events with name event
and the namespace uuid:755e2d2d-a836-4539-83f4-16b51156341f
or null, that are targetted at or bubble through the element.
UAs must also support all the common attributes on the event-source
element.
RemoteEventTarget
interfaceAny object that implements the EventTarget
interface shall also implement the RemoteEventTarget
interface.
interface RemoteEventTarget { void addEventSource(in DOMString src); void removeEventSource(in DOMString src);};
The addEventSource(src)
method shall register the URI (or IRI) specified in src as an event source on the object. The removeEventSource(src)
method shall remove the URI (or IRI) specified in src from the list of event sources for that object. If a single URI is added multiple times, each instance must be handled individually. Removing a URI must only remove one instance of that URI. If the specified URI cannot be added or removed, the method must return without doing anything or raising an exception.
When an event-source
element in a document has a src
attribute set, the UA should fetch the resource indicated by the attribute's value.
Similarly, when the addEventSource()
method is invoked on an object, the UA should, at the completion of the script's current execution, fetch the resource identified by the method's argument (unless the removeEventSource()
was called removing the URI from the list first).
When an event-source
element is removed from the document, or when an event source is removed from the list of event sources for an object using the removeEventSource()
method, the relevant connection must be closed (and not reopened unless the element is returned to the document or the addEventSource()
method is called with the same URI again).
Should event-source elements be allowed to point to any remote server, or only origin hosts?
Since connections established to remote servers for such resources are expected to be long-lived, UAs should ensure that appropriate buffering is used. In particular, while line buffering may be safe if lines are defined to end with a single U+000A LINE FEED character, block buffering or line buffering with different expected line endings can cause delays in event dispatch.
In general, the semantics of the transport protocol specified by the "src" attribute must be followed. Clients should re-open event-source
connections that get closed after a short interval (such as 5 seconds), unless they were closed due to problems that aren't expected to be resolved, as described in this section.
DNS errors must be considered fatal, and cause the user agent to not open any connection for the event-source.
HTTP 200 OK responses that have a Content-Type other than application/x-dom-event-stream
must be ignored and must prevent the user agent from reopening the connection for that event-source. HTTP 200 OK responses with the right MIME type, however, should, when closed, be reopened after a small delay.
Resource with the type application/x-dom-event-stream
must be processed line by line as described below.
HTTP 201 Created, 202 Accepted, 203 Non-Authoritative Information, and 206 Partial Content responses must be treated like HTTP 200 OK responses for the purposes of reopening event-source connections. They are, however, likely to indicate an error has occurred somewhere and may cause the user agent to emit a warning.
HTTP 204 No Content, and 205 Reset Content responses must be treated as if they were 200 OK responses with the right MIME type but no content, and should therefore cause the user agent to reopen the connection after a short delay.
HTTP 300 Multiple Choices responses should be handled automatically if possible (treating the responses as if they were 302 Moved Permanently responses pointing to the appropriate resource), and otherwise must be treated as HTTP 404 responses.
HTTP 301 Moved Permanently responses must cause the user agent to use the server specified URI instead of the one specified in the event-source's "src" attribute for future connections.
HTTP 302 Found, 303 See Other, and 307 Temporary Redirect responses must cause the user agent to use the server specified URI instead of the one specified in the event-source's "src" attribute for the next connection, but if the user agent needs to reopen the connection at a later point, it must once again start from the "src" attribute (or the last URI given by a 301 Moved Permanently response in complicated cases where such responses are chained).
HTTP 304 Not Modified responses should be handled like HTTP 200 OK responses, with the content coming from the user agent cache. A new connection attempt should then be made after a short wait.
HTTP 305 Use Proxy, HTTP 401 Unauthorized, and 407 Proxy Authentication Required should be treated transparently as for any other subresource.
HTTP 400 Bad Request, 403 Forbidden, 404 Not Found, 405 Method Not Allowed, 406 Not Acceptable, 408 Request Timeout, 409 Conflict, 410 Gone, 411 Length Required, 412 Precondition Failed, 413 Request Entity Too Large, 414 Request-URI Too Long, 415 Unsupported Media Type, 416 Requested Range Not Satisfiable, 417 Expectation Failed, 500 Internal Server Error, 501 Not Implemented, 502 Bad Gateway, 503 Service Unavailable, 504 Gateway Timeout, and 505 HTTP Version Not Supported responses, and any other HTTP response code not listed here, should cause the user agent to stop trying to process this event-source element.
For non-HTTP protocols, UAs should act in equivalent ways.
The event stream MIME type is application/x-dom-event-stream
.
The event stream must always be encoded as UTF-8. Line must always be terminated by a single U+000A LINE FEED character.
The event stream format is (in pseudo-BNF):
AMPERSANDlt;streamAMPERSANDgt; ::= AMPERSANDlt;eventAMPERSANDgt;*AMPERSANDlt;eventAMPERSANDgt; ::= [ AMPERSANDlt;commentAMPERSANDgt; | AMPERSANDlt;commandAMPERSANDgt; | AMPERSANDlt;fieldAMPERSANDgt; ]* AMPERSANDlt;newlineAMPERSANDgt;AMPERSANDlt;commentAMPERSANDgt; ::= ';' AMPERSANDlt;dataAMPERSANDgt; AMPERSANDlt;newlineAMPERSANDgt;AMPERSANDlt;commandAMPERSANDgt; ::= ':' AMPERSANDlt;dataAMPERSANDgt; AMPERSANDlt;newlineAMPERSANDgt;AMPERSANDlt;fieldAMPERSANDgt; ::= AMPERSANDlt;nameAMPERSANDgt; [ ':' AMPERSANDlt;spaceAMPERSANDgt;? AMPERSANDlt;dataAMPERSANDgt; ]? AMPERSANDlt;newlineAMPERSANDgt;AMPERSANDlt;nameAMPERSANDgt; ::= one or more UNICODE characters other than ':', ';', and U+000A LINE FEEDAMPERSANDlt;dataAMPERSANDgt; ::= zero or more UNICODE characters other than U+000A LINE FEEDAMPERSANDlt;spaceAMPERSANDgt; ::= a single U+0020 SPACE character (' ')AMPERSANDlt;newlineAMPERSANDgt; ::= a single U+000A LINE FEED character
Bytes that are not valid UTF-8 sequences must be interpreted as the U+FFFD REPLACEMENT CHARACTER.
The stream is parsed by reading everything line by line, in blocks separated by blank lines (blank lines are those consisting of just a single lone line feed character). Comment lines (those starting with the character ';') and command lines (those starting with the character ':') are ignored. Command lines are reserved for future use and should not be used.
For each non-blank, non-comment line, the field name is first taken. This is everything on the line up to but not including the first colon (':') or the line feed, whichever comes first. Then, if there was a colon, the data for that line is taken. This is everything after the colon, ignoring a single space after the colon if there is one, up to the end of the line. If there was no colon the data is the empty string.
Examples:
Field name: Field data
This is a blank field
1. These two lines: have the same data2. These two lines:have the same data
1. But these two lines: do not2. But these two lines: do not
If a field name occurs multiple times, the data values for those lines are concatenated with a newline between them.
For example, the following:
Test: Line 1Foo: BarTest: Line 2
...is treated as having two fields, one called Test
with the value Line 1\nLine 2
(where \n
represents a newline), and one called Foo
with the value Bar
.
Since any random stream of characters matches the above format, there is no need to define any error handling.
Once the fields have been parsed, they are interpreted as follows (these are case-sensitive exact comparisons):
Event
is the name of the event. For example, load
, DOMActivate
, updateTicker
. If there is no field with this name, then no event will be synthesised, and the other data will be ignored.
Namespace
is the DOM3 namespace for the event. For normal DOM events this would be http://www.w3.org/2001/xml-events
. If it isn't specified the event namespace is null.
Class
is the interface used for the event, for instance Event
, UIEvent
, MutationEvent
, KeyboardEvent
, etc. For compatibility with DOM3 Events, the values UIEvents
, MouseEvents
, MutationEvents
, and HTMLEvents
are valid values and must be treated respectively as meaning the interfaces UIEvent
, MouseEvent
, MutationEvent
, and Event
. (This value can therefore be used as the argument to createEvent()
.) If the value is not specified it is defaulted based on the event name as follows:
If Namespace
is http://www.w3.org/2001/xml-events
or null and the Event
field exactly matches one of the events specified by DOM3 Events in section 1.4.2 "Complete list of event types", then the Class defaults to the interface relevant for that event type. [DOM3EVENTS]
For example:
Event: click
...would cause Class
to be treated as MouseEvent
.
If Namespace
is uuid:755e2d2d-a836-4539-83f4-16b51156341f
or null and the Event
doesn't match any of the known events, then the RemoteEvent
interface (described below) is used.
Otherwise, if the UA doesn't have special knowledge of which class to use for the given event in the given namespace, then the Event
interface is used.
It is quite possible to give the wrong class for an event. This is equivalent to creating an event in the DOM using the DOM Event APIs, but using the wrong interface for it.
Bubbles
specifies whether the event is to bubble. If it is specified and has the value No
, the event does not bubble. If it is specified and has any other value (including no
or No\n
) then the event bubbles. If it is not specified it is defaulted based on the event name as follows:
If Namespace
is http://www.w3.org/2001/xml-events
or null and the Event
field exactly matches one of the events specified by DOM3 Events in section 1.4.2 "Complete list of event types", then whether the event bubbles depends on whether the DOM3 Events spec specifies that that event should bubble or not. [DOM3EVENTS]
For example:
Event: load
...would cause Bubbles
to be treated as No
.
Otherwise, if the UA doesn't have special knowledge of which class to use for the given event in the given namespace, then the event bubbles.
Cancelable
specifies whether the event may have its default action prevented. If it is specified and has the value No
, the event may not have its default action prevented. If it is specified and has any other value (including no
or No\n
) then the event may be canceled. If it is not specified it is defaulted based on the event name as follows:
If Namespace
is http://www.w3.org/2001/xml-events
or null and the Event
field exactly matches one of the events specified by DOM3 Events in section 1.4.2 "Complete list of event types", then whether the event is cancelable depends on whether the DOM3 Events spec specifies that that event should be cancelable or not. [DOM3EVENTS]
For example:
Event: load
...would cause Cancelable
to be treated as No
.
Otherwise, if the UA doesn't have special knowledge of which class to use for the given event in the given namespace, then the event may be canceled.
Target
is the element that the event is to be dispatched on. If its value starts with a #
character then the remainder of the value represents an ID, and the event must be dispatched on the same node as would be obtained by the getElementById()
method on the ownerDocument of the event-source element responsible for the event being dispatched.
For example,
Target: #test
...would target the element with ID test
.
If the value does not start with a #
but has the literal value Document
, then the event is dispatched at the ownerDocument
of the event-source
element responsible for the event being dispatched.
Otherwise, the event is dispatched at the event-source
element itself.
Other fields depend on the interface specified (or possibly implied) by the Class
field. If the specified interface has an attribute that exactly matches the name of the field, and the value of the field can be converted (using the type conversions defined in ECMAScript) to the type of the attribute, then it must be used. Any attributes (other than the Event
interface attributes) that do not have matching fields are initialised to zero, null, false, or the empty string.
For example:
; ...some other fields...Class: MouseEventbutton: 2
...would result in a MouseEvent event that had button
set to 2
but screenX
, screenY
, etc, set to 0, false, or null as appropriate.
If a field does not match any of the attributes on the event, it is ignored.
For example:
Event: keypressClass: MouseEventkeyIdentifier: 0
...would result in a MouseEvent
event with its fields all at their default values, with the event name being keypress
. The ctrlKey
field would be ignored. (If the author had not included the Class
field explicitly, it would have just worked, since the class would have defaulted as described above.)
Once a blank line is reached, an event of the appropriate type is synthesized and dispatched to the appropriate node as described by the fields above. No event is dispatched until a blank line has been received.
If the Event
field was omitted, then no event is synthesised and the data is ignored.
The following stream contains four blocks yet synthesises no events, since none of the blocks have a field called Event
. (The first block has just a comment, the second block has two fields with names "load" and "Target" respectively, the third block is empty, and the fourth block has two comments.)
; testloadTarget: #image1; if any real events follow this block, they will not be affected by; the "Target" and "load" fields above.
RemoteEvent
interfaceThe RemoteEvent
interface is defined as follows:
interface RemoteEvent : Event { readonly attribute DOMString data; void initRemoteEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg); void initRemoteEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg);};
Events that use the RemoteEvent
interface never have any default action associated with them.
I guess we should define those members.
The following event description, once followed by a blank line:
Event: stock changedata: YHOOdata: -2data: 10
...would cause an event stock change
with the interface RemoteEvent
to be dispatched on the event-source
element, which would then bubble up the DOM, and whose data
attribute would contain the string YHOO\n-2\n10
(where \n
again represents a newline).
This could be used as follows:
AMPERSANDlt;event-source src="http://stocks.example.com/ticker.php" id="stock"AMPERSANDgt;AMPERSANDlt;script type="text/javascript"AMPERSANDgt;document.getElementById('stock').addEventListener('stock change', function () { var data = event.data.split('\n'); updateStocks(data[0], data[1], data[2]); }, false);AMPERSANDlt;/scriptAMPERSANDgt
...where updateStocks is a function defined as:
function updateStocks(symbol, delta, value) { ... }
...or some such.
To enable Web applications to communicate with each other in local area networks, and to maintain bidirectional communications with their originating server, this specification introduces the Connection
interface.
The WindowHTML
interface provides three constructors for creating Connection
objects: TCPConnection()
, for creating a direct (possibly encrypted) link to another node on the Internet using TCP/IP; LocalBroadcastConnection()
, for creating a connection to any listening peer on a local network (which could be a local TCP/IP subnet using UDP, a Bluetooth PAN, or another kind of network infrastructure); and PeerToPeerConnection()
, for a direct peer-to-peer connection (which could again be over TCP/IP, Bluetooth, IrDA, or some other type of network).
This interface does not allow for raw access to the underlying network. For example, this interface could not be used to implement an IRC client without proxying messages through a custom server.
This section is non-normative.
An introduction to the client-side and server-side of using the direct connection APIs.
An example of a party-line implementation of a broadcast service, and direct peer-to-peer chat for direct local connections.
Connection
interfaceinterface Connection { readonly attribute DOMString network; readonly attribute DOMString peer; readonly attribute int readyState; attribute EventListener onopen; attribute EventListener onread; attribute EventListener onclose; void send(in DOMString data); void disconnect();};
Connection
objects must also implement the EventTarget
interface. [DOM3EVENTS]
When a Connection
object is created, the UA must try to establish a connection, as described in the sections below describing each connection type.
The network
attribute represents the name of the network connection (the value depends on the kind of connection being established). The peer
attribute identifies the remote host for direct (non-broadcast) connections.
The network
attribute must be set as soon as the Connection
object is created, and keeps the same value for the lifetime of the object. The peer
attribute must initially be set to the empty string and must be updated once, when the connection is established, after which point it must keep the same value for the lifetime of the object.
The readyState
attribute represents the state of the connection. When the object is created it must be set to 0. It can have the following values:
Once a connection is established, the readyState
attribute's value must be changed to 1, and the open
event must be fired on the Connection
object.
When data is received, the read
event will be fired on the Connection
object.
When the connection is closed, the readyState
attribute's value must be changed to 2, and the close
event must be fired on the Connection
object.
The onopen
, onread
, and onclose
attributes must, when set, register their new value as an event listener for their respective events (namely open
, read
, and close
), and unregister their previous value if any.
The send()
method transmits data using the connection. If the connection is not yet established, it must raise an INVALID_STATE_ERR
exception. If the connection is established, then the behaviour depends on the connection type, as described below.
The disconnect()
method must close the connection, if it is open. If the connection is already closed, it must do nothing. Closing the connection causes a close
event to be fired and the readyState
attribute's value to change, as described above.
All the events described in this section are events in the http://www.w3.org/2001/xml-events
namespace, which do not bubble, are not cancelable, and have no default action.
The open
event is fired when the connection is established. UAs must use the normal Event
interface when firing this event.
The close
event is fired when the connection is closed (whether by the author, calling the disconnect()
method, or by the server, or by a network error). UAs must use the normal Event
interface when firing this event as well.
No information regarding why the connection was closed is passed to the application in this version of this specification.
The read
event is fired when when data is received for a connection. UAs must use the ConnectionReadEvent
interface for this event.
interface ConnectionReadEvent : Event { readonly attribute DOMString data; readonly attribute DOMString source; void initConnectionReadEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg); void initConnectionReadEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg);};
The data
attribute must contain the data that was transmitted from the peer.
The source
attribute must contain the name of the peer. This is primarily useful on broadcast connections; on direct connections it is equal to the peer
attribute on the Connection
object.
The initConnectionReadEvent()
and initConnectionReadEventNS()
methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
Events that would be fired during script execution (e.g. between the connection object being created AMPERSANDmdash; and thus the connection being established AMPERSANDmdash; and the current script completing; or, during the execution of a read
event handler) must be buffered, and those events queued up and each one individually fired after the script has completed.
The TCPConnection(subdomain, port, secure)
constructor on the WindowHTML
interface returns a new object implementing the Connection
interface, set up for a direct connection to a specified host on the page's domain.
When this constructor is invoked, the following steps must be followed.
First, if the script's domain is not a host name (e.g. it is an IP address) then the UA must raise a security exception. We currently don't allow connections to be set up back to an originating IP address, but we could, if the subdomain is the empty string.
Then, if the subdomain argument is null or the empty string, the target host is the script's domain. Otherwise, the subdomain argument is prepended to the script's domain with a dot separating the two strings, and that is the target host.
If either:
...then the UA must raise a security exception.
Otherwise, the user agent must verify that the the string representing the script's domain in IDNA format can be obtained without errors. If it cannot, then the user agent must raise a security exception.
The user agent may also raise a security exception at this time if, for some reason, permission to create a direct TCP connection to the relevant host is denied. Reasons could include the UA being instructed by the user to not allow direct connections, or the UA establishing (for instance using UPnP) that the network topology will cause connections on the specified port to be directed at the wrong host.
If no exceptions are raised by the previous steps, then a new Connection
object must be created, its peer
attribute must be set to a string consisting of the name of the target host, a colon (U+003A COLON), and the port number as decimal digits, and its network
attribute must be set to the same value as the peer
attribute.
This object must then be returned.
The user agent must then begin trying to establish a connection with the target host and specified port. (This typically would begin in the backgound, while the script continues to execute.)
If the secure boolean argument is set to true, then the user agent must establish a secure connection with the target host and specified port using TLS or another protocol, negotiated with the server. [RFC2246] If this fails the user agent must act as if it had closed the connection.
Once a secure connection is established, or if the secure boolean argument is not set to true, then the user agent must continue to connect to the server using the protocol described in the section entitled clients connecting over TCP. All data on connections made using TLS must be sent as "application data".
Once the connection is established, the UA must act as described in the section entitled sending and receiving data over TCP.
User agents should allow multiple TCP connections to be established per host. In particular, user agents should not apply per-host HTTP connection limits to connections established with the TCPConnection
constructor.
The LocalBroadcastConnection()
constructor on the WindowHTML
interface returns a new object implementing the Connection
interface, set up to broadcast on the local network.
When this constructor is invoked, a new Connection
object must be created.
The network
attribute of the object must be set to the string representing the script's domain in IDNA format. If this string cannot be obtained, then the user agent must raise a security exception exception when the constructor is called.
The peer
attribute must be set to the empty string.
The object must then be returned, unless, for some reason, permission to broadcast on the local network is to be denied. In the latter case, a security exception must be raised instead. User agents may deny such permission for any reason, for example a user preference.
If the object is returned (i.e. if no exception is raised), the user agent must the begin broadcasting and listening on the local network, in the background, as described below. The user agent may define "the local network" in any way it considers appropriate and safe; for instance the user agent may ask the user which network (e.g. Bluetooth, IrDA, Ethernet, etc) the user would like to broadcast on before beginning broadcasting.
UAs may broadcast and listen on multiple networks at once. For example, the UA could broadcast on both Bluetooth and Wifi at the same time.
As soon as the object is returned, the connection has been established, which implies that the open
event must be fired. Broadcast connections are never closed.
Should we drop this altogether? Letting people fill the local network with garbage seems unwise.
We need to register a UDP port for this. For now this spec refers to port 18080/udp.
Since this feature requires that the user agent listen to a particular port, some platforms might prevent more than one user agent per IP address from using this feature at any one time.
On TCP/IP networks, broadcast connections transmit data using UDP over port 18080.
When the send(data)
method is invoked on a Connection
object that was created by the LocalBroadcastConnection()
constructor, the user agent must follow these steps:
network
attribute of the Connection
object, a U+0020 SPACE character, a U+0002 START OF TEXT character, and the data argument. INDEX_SIZE_ERR
DOM exception and stop. When a broadcast connection is opened on a TCP/IP network, the user agent should listen for UDP packets on port 18080.
When the user agent receives a packet on port 18080, the user agent must attempt to decode that packet's data as UTF-8. If the data is not fully correct UTF-8 (i.e. if there are decoding errors) then the packet must be ignored. Otherwise, the user agent must check to see if the decoded string contains a U+0020 SPACE character. If it does not, then the packet must again be ignored (it might be a peer discovery packet from a PeerToPeerConnection()
constructor). If it does then the user agent must split the string at the first space character. All the characters before the space are then known as d, and all the characters after the space are known as s. If s is not at least one character long, or if the first character of s is not a U+0002 START OF TEXT character, then the packet must be ignored. (This allows for future extension of this protocol.)
Otherwise, for each Connection
object that was created by the LocalBroadcastConnection()
constructor and whose network
attribute exactly matches d, a read
event must be fired on the Connection
object. The string s, with the first character removed, must be used as the data
, and the source IP address of the packet as the source
.
Making the source IP available means that if two or more machines in a private network can be made to go to a hostile page simultaneously, the hostile page can determine the IP addresses used locally (i.e. on the other side of any NAT router). Is there some way we can keep link-local IP addresses secret while still allowing for applications to distinguish between multiple participants?
Does anyone know enough about Bluetooth to write this section?
Does anyone know enough about IrDA to write this section?
The PeerToPeerConnection()
constructor on the WindowHTML
interface returns a new object implementing the Connection
interface, set up for a direct connection to a user-specified host.
When this constructor is invoked, a new Connection
object must be created.
The network
attribute of the object must be set to the string representing the script's domain in IDNA format. If this string cannot be obtained, then the user agent must raise a security exception exception when the constructor is called.
The peer
attribute must be set to the empty string.
The object must then be returned, unless, for some reason, permission to establish peer-to-peer connections is generally disallowed, for example due to administrator settings. In the latter case, a security exception must be raised instead.
The user agent must then, typically while the script resumes execution, find a remote host to establish a connection to. To do this it must start broadcasting and listening for peer discovery messages and listening for incoming connection requests on all the supported networks. How this is performed depends on the type of network and is described below.
The UA should inform the user of the clients that are detected, and allow the user to select one to connect to. UAs may also allow users to explicit specify hosts that were not detected, e.g. by having the user enter an IP address.
If an incoming connection is detected before the user specifies a target host, the user agent should ask the user to confirm that this is the host they wish to connect to. If it is, the connection should be accepted and the UA will act as the server in this connection. (Which UA acts as the server and which acts as the client is not discernible at the DOM API level.)
If no incoming connection is detected and if the user specifies a particular target host, a connection should be established to that host, with the UA acting as the client in the connection.
No more than one connection must be established per Connection
object, so once a connection has been established, the user agent must stop listening for further connections (unless, or until such time as, another Connection
object is being created).
If at any point the user cancels the connection process or the remote host refuses the connection, then the user agent must act as if it had closed the connection, and stop trying to connect.
Should we replace this section with something that uses Rendez-vous/zeroconf or equivalent?
We need to register ports for this. For now this spec refers to port 18080/udp and 18080/tcp.
Since this feature requires that the user agent listen to a particular port, some platforms might prevent more than one user agent per IP address from using this feature at any one time.
When using TCP/IP, broadcasting peer discovery messages must be done by creating UDP packets every few seconds containing as their data the value of the connection's network
attribute, encoded as UTF-8, with the source and destination ports being set to 18080 and appropriate length and checksum fields, and sending these packets to address (in IPv4) 255.255.255.255 or (in IPv6) ff02::1, as appropriate.
Listening for peer discovery messages must be done by examining incoming UDP packets on port 18080. IPv6 applications will also have to enable reception from the ff02::1 address. If their payload is exactly byte-for-byte equal to a UTF-8 encoded version of the value of the connection's network
attribute, then the source address of that packet represents the address of a host that is ready to accept a peer-to-peer connection, and it should therefore be offered to the user.
Incoming connection requests must be listened for on TCP port 18080. If an incoming connection is received, the UA must act as a server, as described in the section entitled servers accepting connections over TCP.
If no incoming connection requests are accepted and the user instead specifies a target host to connect to, the UA acts as a client: the user agent must attempt to connect to the user-specified host on port 18080, as described in the section entitled clients connecting over TCP.
Once the connection is established, the UA must act as described in the section entitled sending and receiving data over TCP.
This specification does not include a way to establish secure (encrypted) peer-to-peer connections at this time. If you can see a good way to do this, let me know.
Does anyone know enough about Bluetooth to write this section?
Does anyone know enough about IrDA to write this section?
The same protocol is used for TCPConnection
and PeerToPeerConnection
connection types. This section describes how such connections are established from the client and server sides, and then describes how data is sent and received over such connections (which is the same for both clients and servers).
This section defines the client-side requirements of the protocol used by the TCPConnection
and PeerToPeerConnection
connection types.
If a TCP connection to the specified target host and port cannot be established, for example because the target host is a domain name that cannot be resolved to an IP address, or because packets cannot be routed to the host, the user agent should retry creating the connection. If the user agent gives up trying to connect, the user agent must act as if it had closed the connection.
No information regarding the state of the connection is passed to the application while the connection is being established in this version of this specification.
Once a TCP/IP connection to the remote host is established, the user agent must transmit the following sequence of bytes, represented here in hexadecimal form:
0x48 0x65 0x6C 0x6C 0x6F 0x0A
This represents the string "Hello" followed by a newline, encoded in UTF-8.
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes is then compared byte-for-byte to the following string of bytes:
0x57 0x65 0x6C 0x63 0x6F 0x6E 0x65 0x0A
This says "Welcome".
If the server sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the user agent must then take the string representing the script's domain in IDNA format, encode it as UTF-8, and send that to the remote host, followed by a 0x0A byte (a U+000A LINE FEED in UTF-8).
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes must then be compared byte-for-byte to the string that was just sent to the server (the one with the IDNA domain name and ending with a newline character). If the server sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the connection has been established (and events and so forth get fired, as described above).
If at any point during this process the connection is closed prematurely, then the user agent must close the connection and give up trying to connect.
This section defines the server side of the protocol described in the previous section. For authors, it should be used as a guide for how to implement servers that can communicate with Web pages over TCP. For UAs these are the requirements for the server part of PeerToPeerConnection
s.
Once a TCP/IP connection from a remote host is established, the user agent must transmit the following sequence of bytes, represented here in hexadecimal form:
0x57 0x65 0x6C 0x63 0x6F 0x6E 0x65 0x0A
This says "Welcome" and a newline in UTF-8.
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes is then compared byte-for-byte to the following string of bytes:
0x48 0x65 0x6C 0x6C 0x6F 0x0A
"Hello" and a newline.
If the remote host sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the user agent must then take the string representing the script's domain in IDNA format, encode it as UTF-8, and send that to the remote host, followed by a 0x0A byte (a U+000A LINE FEED in UTF-8).
The user agent must then read all the bytes sent from the remote host, up to the first 0x0A byte (inclusive). That string of bytes must then be compared byte-for-byte to the string that was just sent to that host (the one with the IDNA domain name and ending with a newline character). If the remote host sent back a string in any way different to this, then the user agent must close the connection and give up trying to connect.
Otherwise, the connection has been established (and events and so forth get fired, as described above).
For author-written servers (as opposed to the server side of a peer-to-peer connection), the script's domain would be replaced by the hostname of the server. Alternatively, such servers might instead wait for the client to send its domain string, and then simply echo it back. This would allow connections from pages on any domain, instead of just pages originating from the same host. The client compares the two strings to ensure they are the same before allowing the connection to be used by author script.
If at any point during this process the connection is closed prematurely, then the user agent must close the connection and give up trying to connect.
When the send(data)
method is invoked on the connection's corresponding Connection
object, the user agent must take the data argument, replace any U+0000 NULL and U+0017 END OF TRANSMISSION BLOCK characters in it with U+FFFD REPLACEMENT CHARACTER characters, then transmit a U+0002 START OF TEXT character, this new data string and a single U+0017 END OF TRANSMISSION BLOCK character (in that order) to the remote host, all encoded as UTF-8.
When the user agent receives bytes on the connection, the user agent must buffer received bytes until it receives a 0x17 byte (a U+0017 END OF TRANSMISSION BLOCK character). If the first buffered byte is not a 0x02 byte (a U+0002 START OF TEXT character encoded as UTF-8) then all the data up to the 0x17 byte, inclusive, must be dropped. (This allows for future extension of this protocol.) Otherwise, all the data from (but not including) the 0x02 byte and up to (but not including) the 0x17 byte must be taken, interpreted as a UTF-8 string, and a read
event must be fired on the Connection
object with that string as the data
. If that string cannot be decoded as UTF-8 without errors, the packet should be ignored.
This protocol does not yet allow binary data (e.g. an image or video data) to be efficiently transmitted. A future version of this protocol might allow this by using the prefix character U+001F INFORMATION SEPARATOR ONE, followed by binary data which uses a particular byte (e.g. 0xFF) to encode byte 0x17 somehow (since otherwise 0x17 would be treated as transmission end by down-level UAs).
Need to write this section.
If you have an unencrypted page that is (through a man-in-the-middle attack) changed, it can access a secure service that is using IP authentication and then send that data back to the attacker. Ergo we should probably stop unencrypted pages from accessing encrypted services, on the principle that the actual level of security is zero. Then again, if we do that, we prevent insecure sites from using SSL as a tunneling mechanism.
Should consider dropping the subdomain-only restriction. It doesn't seem to add anything, and prevents cross-domain chatter.
Should have a section talking about the fact that we blithely ignoring IANA's port assignments here.
Should explain why we are not reusing HTTP for this. (HTTP is too heavy-weight for such a simple need; requiring authors to implement an HTTP server just to have a party line is too much of a barrier to entry; cannot rely on prebuilt components; having a simple protocol makes it much easier to do RAD; HTTP doesn't fit the needs and doesn't have the security model needed; etc)
Web browsers, for security and privacy reasons, prevent documents in different domains from affecting each other; that is, cross-site scripting is disallowed.
While this is an important security feature, it prevents pages from different domains from communicating even when those pages are not hostile. This section introduces a messaging system that allows documents to communicate with each other regardless of their source domain, in a way designed to not enable cross-site scripting attacks.
When a script invokes the postMessage(message)
method on a Document
object, the user agent must create an event that uses the CrossDocumentMessageEvent
interface, with the event name message
, which bubbles, is cancelable, and has no default action. The data
attribute must be set to the value passed as the message argument to the postMessage()
method, the domain
attribute must be set to the domain of the document that the script that invoked the methods is associated with, the uri
attribute must be set to the URI of that document, and the source
attribute must be set to the Document
object representing that document.
Authors should check the domain
attribute to ensure that messages are only accepted from domains that they expect to receive messages from. Otherwise, bugs in the author's message handling code could be exploited by hostile sites.
For example, if document A contains an object
element that contains document B, and script in document A calls postMessage()
on document B, then a message event will be fired on that element, marked as originating from document A. The script in document A might look like:
var o = document.getElementsByTagName('object')[0];o.contentDocument.postMessage('Hello world');
To register an event handler for incoming events, the script would use addEventListener()
(or similar mechanisms). For example, the script in document B might look like:
document.addEventListener('message', receiver, false);function receiver(e) { if (e.domain == 'example.com') { if (e.data == 'Hello world') { e.source.postMessage('Hello'); } else { alert(e.data); } }}
This script first checks the domain is the expected domain, and then looks at the message, which it either displays to the user, or responds to by sending a message back to the document which sent the message in the first place.
Implementors are urged to take extra care in the implementation of this feature. It allows authors to transmit information from one domain to another domain, which is normally disallowed for security reasons. It also requires that UAs be careful to allow access to certain properties but not others.
The postMessage() method causes an event to be dispatched (as defined above). This event uses the following interface:
interface CrossDocumentMessageEvent : Event { readonly attribute DOMString data; readonly attribute DOMString domain; readonly attribute DOMString uri; readonly attribute Document source; void initCrossDocumentMessageEvent(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg, in DOMString domainArg, in DOMString uriArg, in Document documentArg); void initCrossDocumentMessageEventNS(in DOMString namespaceURI, in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString dataArg, in DOMString domainArg, in DOMString uriArg, in Document documentArg);};
The data
attribute represents the message being sent.
The domain
attribute represents the domain of the document from which the message came.
The uri
attribute represents the address of the document from which the message came.
The source
attribute represents the Document
from which the message came.
The initCrossDocumentMessageEvent()
and initCrossDocumentMessageEventNS()
methods must initialise the event in a manner analogous to the similarly-named methods in the DOM3 Events interfaces. [DOM3EVENTS]
This section only applies to documents, authoring tools, and markup generators. In particular, it does not apply to conformance checkers; conformance checkers must use the requirements given in the next section ("parsing HTML documents").
Documents must consist of the following parts, in the given order:
html
element. The various types of content mentioned above are described in the next few sections.
A DOCTYPE is a mostly useless, but required, header.
DOCTYPEs are required for legacy reasons. When omitted, browsers tend to use a different rendering mode that is incompatible with some specifications. Including the DOCTYPE in a document ensures that the browser makes a best-effort attempt at following the relevant specifications.
A DOCTYPE must consist of the following characters, in this order:
AMPERSANDlt;
) character. !
) character. AMPERSANDgt;
) character. In other words, AMPERSANDlt;!DOCTYPE HTML>
, case-insensitively.
There are four different kinds of elements: void elements, CDATA elements, RCDATA elements, and normal elements.
base
, link
, meta
, hr
, br
, img
, embed
, param
, area
, col
, input
style
, script
title
, textarea
Tags are used to delimit the start and end of elements in the markup. CDATA, RCDATA, and normal elements have a start tag to indicate where they begin, and an end tag to indicate where they end. The start and end tags of certain normal elements can be omitted, as described later. Those that cannot be omitted must not be omitted. Void elements only have a start tag; end tags must not be specified for void elements.
The contents of the element must be placed between just after the start tag (which might be implied, in certain cases) and just before the end tag (which again, might be implied in certain cases). The exact allowed contents of each individual element depends on the content model of that element, as described earlier in this specification. Elements must not contain content that their content model disallows. In addition to the restrictions placed on the contents by those content models, however, the four types of elements have additional syntactic requirements.
Void elements can't have any contents (since there's no end tag, no content can be put between the start tag and the end tag.)
CDATA elements can have text, but the text must not contain the two character sequence "AMPERSANDlt;/
" (U+003C LESS-THAN SIGN, U+002F SOLIDUS).
RCDATA elements can have text and character entity references, but the text must not contain the character U+003C LESS-THAN SIGN (AMPERSANDlt;
) or the character U+0026 AMPERSAND (AMPERSANDamp;
).
Normal elements can have text, character entity references, other elements, and comments, but the text must not contain the character U+003C LESS-THAN SIGN (AMPERSANDlt;
) or the character U+0026 AMPERSAND (AMPERSANDamp;
). Some normal elements also have yet more restrictions on what content they are allowed to hold, beyond the restrictions imposed by the content model and those described in this paragraph. Those restrictions are described below.
Tags contain a tag name, giving the element's name. HTML elements all have names that only use characters in the range U+0061 LATIN SMALL LETTER A .. U+007A LATIN SMALL LETTER Z, or, in uppercase, U+0041 LATIN CAPITAL LETTER A .. U+005A LATIN CAPITAL LETTER Z, and U+002D HYPHEN-MINUS (-
). In the HTML syntax, tag names may be written with any mix of lower- and uppercase letters that, when converted to all-lowercase, matches the element's tag name; tag names are case-insensitive.
Start tags must have the following format:
AMPERSANDlt;
). /
) character. This character has no effect except to appease the markup gods. As this character is therefore just a symbol of faith, atheists should omit it. AMPERSANDgt;
) character. End tags must have the following format:
AMPERSANDlt;
). /
). AMPERSANDgt;
) character. Attributes for an element are expressed inside the element's start tag.
Attributes have a name and a value. Attribute names use characters in the range U+0061 LATIN SMALL LETTER A .. U+007A LATIN SMALL LETTER Z, or, in uppercase, U+0041 LATIN CAPITAL LETTER A .. U+005A LATIN CAPITAL LETTER Z, and U+002D HYPHEN-MINUS (-
). In the HTML syntax, attribute names may be written with any mix of lower- and uppercase letters that, when converted to all-lowercase, matches the attribute's name; attribute names are case-insensitive.
Attribute values are a mixture of text and character entity references, except with the additional restriction that the text cannot contain a U+0026 AMPERSAND (AMPERSANDamp;
) character.
Attributes can be specified in four different ways:
Just the attribute name.
In the following example, the disabled
attribute is given with the empty attribute syntax:
AMPERSANDlt;input disabledAMPERSANDgt;
If an attribute using the empty attribute syntax is to be followed by another attribute, then there must be a space character separating the two.
The attribute name, followed by zero or more space characters, followed by a single U+003D EQUALS SIGN character, followed by zero or more space characters, followed by the attribute value, which, in addition to the requirements given above for attribute values, must not contain any literal space characters, U+003E GREATER-THAN SIGN (AMPERSANDgt;
) characters, or U+003C LESS-THAN SIGN (AMPERSANDlt;
) characters, and must not, furthermore, start with either a literal U+0022 QUOTATION MARK (AMPERSAND#x22;
) character or a literal U+0027 APOSTROPHE (AMPERSAND#x27;
) character.
In the following example, the value
attribute is given with the unquoted attribute value syntax:
AMPERSANDlt;input value=yesAMPERSANDgt;
If an attribute using the unquoted attribute syntax is to be followed by another attribute or by one of the optional U+002F SOLIDUS (/
) characters allowed in step 6 of the start tag syntax above, then there must be a space character separating the two.
The attribute name, followed by zero or more space characters, followed by a single U+003D EQUALS SIGN character, followed by zero or more space characters, followed by a single U+0027 APOSTROPHE ('
) character, followed by the attribute value, which, in addition to the requirements given above for attribute values, must not contain any literal U+0027 APOSTROPHE ('
) characters, and finally followed by a second single U+0027 APOSTROPHE ('
) character.
In the following example, the type
attribute is given with the single-quoted attribute value syntax:
AMPERSANDlt;input type='checkbox'AMPERSANDgt;
The attribute name, followed by zero or more space characters, followed by a single U+003D EQUALS SIGN character, followed by zero or more space characters, followed by a single U+0022 QUOTATION MARK ("
) character, followed by the attribute value, which, in addition to the requirements given above for attribute values, must not contain any literal U+0022 QUOTATION MARK ("
) characters, and finally followed by a second single U+0022 QUOTATION MARK ("
) character.
In the following example, the name
attribute is given with the double-quoted attribute value syntax:
AMPERSANDlt;input name="be evil"AMPERSANDgt;
Certain tags can be omitted.
An html
element's start tag may be omitted if the first thing inside the html
element is not a space character or a comment.
An html
element's end tag may be omitted if the html
element is not immediately followed by a space character or a comment.
A head
element's start tag may be omitted if the first thing inside the head
element is an element.
A head
element's end tag may be omitted if the head
element is not immediately followed by a space character or a comment.
A body
element's start tag may be omitted if the first thing inside the body
element is not a space character or a comment.
A body
element's end tag may be omitted if the body
element is not immediately followed by a space character or a comment.
A li
element's end tag may be omitted if the li
element is immediately followed by another li
element or if there is no more content in the parent element.
A dt
element's end tag may be omitted if the dt
element is immediately followed by another dt
element or a dd
element.
A dd
element's end tag may be omitted if the dd
element is immediately followed by another dd
element or a dt
element, or if there is no more content in the parent element.
A p
element's end tag may be omitted if the p
element is immediately followed by an address
, blockquote
, dl
, fieldset
, form
, h1
, h2
, h3
, h4
, h5
, h6
, hr
, menu
, ol
, p
, pre
, table
, or ul
element, or if there is no more content in the parent element.
An optgroup
element's end tag may be omitted if the optgroup
element is immediately followed by another optgroup
element, or if there is no more content in the parent element.
An option
element's end tag may be omitted if the option
element is immediately followed by another option
element, or if there is no more content in the parent element.
A colgroup
element's start tag may be omitted if the first thing inside the colgroup
element is a col
element, and if the element is not immediately preceeded by another colgroup
element whose end tag has been omitted.
A colgroup
element's end tag may be omitted if the colgroup
element is not immediately followed by a space character or a comment.
A thead
element's end tag may be omitted if the thead
element is immediately followed by a tbody
or tfoot
element.
A tbody
element's start tag may be omitted if the first thing inside the tbody
element is a tr
element, and if the element is not immediately preceeded by a tbody
, thead
, or tfoot
element whose end tag has been omitted.
A tbody
element's end tag may be omitted if the tbody
element is immediately followed by a tbody
or tfoot
element, or if there is no more content in the parent element.
A tfoot
element's end tag may be omitted if the tfoot
element is immediately followed by a tbody
element, or if there is no more content in the parent element.
A tr
element's end tag may be omitted if the tr
element is immediately followed by another tr
element, or if there is no more content in the parent element.
A td
element's end tag may be omitted if the td
element is immediately followed by a td
or th
element, or if there is no more content in the parent element.
A th
element's end tag may be omitted if the th
element is immediately followed by a td
or th
element, or if there is no more content in the parent element.
However, a start tag must never be omitted if it has any attributes.
For historical reasons, certain elements have extra restrictions beyond even the restrictions given by their content model.
A p
element must not contain blockquote
, dl
, menu
, ol
, pre
, table
, or ul
elements, even though these elements are technically allowed inside p
elements according to the content models described in this specification. (In fact, if one of those elements is put inside a p
element in the markup, it will instead imply a p
element end tag before it.)
An optgroup
element must not contain optgroup
elements, even though these elements are technically allowed to be nested according to the content models described in this specification. (If an optgroup
element is put inside another in the markup, it will in fact imply an optgroup
end tag before it.)
A table
element must not contain tr
elements, even though these elements are technically allowed inside table
elements according to the content models described in this specification. (If a tr
element is put inside a table
in the markup, it will in fact imply a tbody
start tag before it.)
Text is allowed inside elements, attributes, and comments. Text must consist of valid Unicode characters other than U+0000. Text should not contain control characters other than space characters. Extra constraints are placed on what is and what is not allowed in text based on where the text is to be put, as described in the other sections.
Newlines in HTML may be represented either as U+000D CARRIAGE RETURN (CR) characters, U+000A LINE FEED (LF) characters, or pairs of U+000D CARRIAGE RETURN (CR), U+000A LINE FEED (LF) characters in that order.
In certain cases described in other sections, text may be mixed with character entity references. These can be used to escape characters that couldn't otherwise legally be included in text.
Character entity references must start with a U+0026 AMPERSAND (AMPERSANDamp;
). Following this, there are three possible kinds of character entity references:
;
). #
) character, followed by one or more digits in the range U+0030 DIGIT ZERO .. U+0039 DIGIT NINE, representing a base-ten integer that itself is a valid Unicode code point that isn't U+0000. The digits must then be followed by a U+003B SEMICOLON character (;
). #
) character, which must be followed by either a U+0078 LATIN SMALL LETTER X or a U+0058 LATIN CAPITAL LETTER X character, which must then be followed by one or more digits in the range U+0030 DIGIT ZERO .. U+0039 DIGIT NINE, U+0061 LATIN SMALL LETTER A .. U+0066 LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER A .. U+0046 LATIN CAPITAL LETTER F, representing a base-sixteen integer that itself is a valid Unicode code point that isn't U+0000. The digits must then be followed by a U+003B SEMICOLON character (;
). Comments must start with the four character sequence U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS (AMPERSANDlt;!--
). Following this sequence, the comment may have text, with the additional restriction that the text must not contain two consecutive U+002D HYPHEN-MINUS (-
) characters, nor end with a U+002D HYPHEN-MINUS (-
) character. Finally, the comment must be ended by the three character sequence U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN (--AMPERSANDgt;
).
This section only applies to user agents, data mining tools, and conformance checkers.
The rules for parsing XML documents (and thus XHTML documents) into DOM trees are covered by the XML and Namespaces in XML specifications, and are out of scope of this specification.
For HTML documents, user agents must use the parsing rules described in this section to generate the DOM trees. Together, these rules define what is referred to as the HTML parser.
While the HTML form of HTML5 bears a close resemblance to SGML and XML, it is a separate language with its own parsing rules.
Some earlier versions of HTML (in particular from HTML2 to HTML4) were based on SGML and used SGML parsing rules. However, few (if any) web browsers ever implemented true SGML parsing for HTML documents; the only user agents to strictly handle HTML as an SGML application have historically been validators. The resulting confusion AMPERSANDmdash; with validators claiming documents to have one representation while widely deployed Web browsers interoperably implemented a different representation AMPERSANDmdash; has resulted in this version of HTML returning to a non-SGML basis.
Authors interested in using SGML tools in their authoring pipeline are encouraged to use the XML serialisation of HTML5 instead of the HTML serialisation.
This specification defines the parsing rules for HTML documents, whether they are syntactically valid or not. Certain points in the parsing algorithm are said to be parse errors. The error handling for parse errors is well-defined: user agents must either act as described below when encountering such problems, or must abort processing at the first error that they encounter for which they do not wish to apply the rules described below.
Conformance checkers must report at least one parse error condition to the user if one or more parse error conditions exist in the document and must not report parse error conditions if none exist in the document. Conformance checkers may report more than one parse error condition if more than one parse error conditions exist in the document. Conformance checkers are not required to recover from parse errors.
Parse errors are only errors with the syntax of HTML. In addition to checking for parse errors, conformance checkers will also verify that the document obeys all the other conformance requirements described in this specification.
The input to the HTML parsing process consists of a stream of Unicode characters, which is passed through a tokenisation stage (lexical analysis) followed by a tree construction stage (semantic analysis). The output is a Document
object.
Implementations that do not support scripting do not have to actually create a DOM Document
object, but the DOM tree in such cases is still used as the model for the rest of the specification.
In the common case, the data handled by the tokenisation stage comes from the network, but it can also come from script, e.g. using the document.write()
API.
There is only one set of state for the tokeniser stage and the tree construction stage, but the tree construction stage is reentrant, meaning that while the tree construction stage is handling one token, the tokeniser might be resumed, causing further tokens to be emitted and processed before the first token's processing is complete.
In the following example, the tree construction stage will be called upon to handle a "p" start tag token while handling the "script" start tag token:
...AMPERSANDlt;script> document.write('AMPERSANDlt;p>');AMPERSANDlt;/script>...
The stream of Unicode characters that consists the input to the tokenisation stage will be initially seen by the user agent as a stream of bytes (typically coming over the network or from the local file system). The bytes encode the actual characters according to a particular character encoding, which the user agent must use to decode the bytes into characters.
For HTML, user agents must use the following algorithm in determining the character encoding of a document:
meta
element that specifies character encoding information, then use that. (The exact parsing rules for finding and using this information are not yet described in this specification.) This needs to be fleshed out a whole heck of a lot more.ISO-8859-1
, windows-1252
, and UTF-8
are recommended as defaults, and can in many cases be identified by inspection as they have different ranges of valid bytes).For XML documents, the algorithm user agents must use to determine the character encoding is given by the XML specification. This section does not apply to XML documents. [XML]
Bytes or sequences of bytes in the original byte stream that could not be converted to Unicode characters must be converted to U+FFFD REPLACEMENT CHARACTER code points.
A leading U+FEFF BYTE ORDER MARK (BOM) must be dropped if present.
All U+0000 NULL characters in the input must be replaced by U+FFFD REPLACEMENT CHARACTERs.
U+000D CARRIAGE RETURN (CR) characters, and U+000A LINE FEED (LF) characters, are treated specially. Any CR characters that are followed by LF characters must be removed, and any CR characters not followed by LF characters must be converted to LF characters. Thus, newlines in HTML DOMs are represented by LF characters, and there are never any CR characters in the input to the tokenisation stage.
The next input character is the first character in the input stream that has not yet been consumed. Initially, the next input character is the first character in the input.
The insertion point is the position (just before a character or just before the end of the input stream) where content inserted using document.write()
is actually inserted. The insertion point is relative to the position of the character immediately after it, it is not an absolute offset into the input stream. Initially, the insertion point is uninitialised.
The "EOF" character in the tables below is a conceptual character representing the end of the input stream. If the parser is a script-created parser, then the end of the input stream is reached when an explicit "EOF" character (inserted by the document.close()
method) is consumed. Otherwise, the "EOF" charecter is not a real character in the stream, but rather the lack of any further characters.
Implementations must act as if they used the following state machine to tokenise HTML. The state machine must start in the data state. Most states consume a single character, which may have various side-effects, and either switches the state machine to a new state to reconsume the same character, or switches it to a new state (to consume the next character), or repeats the same state (to consume the next character). Some states have more complicated behaviour and can consume several characters before switching to another state.
The exact behaviour of certain states depends on a content model flag that is set after certain tokens are emitted. The flag has several states: PCDATA, RCDATA, CDATA, and PLAINTEXT. Initially it is in the PCDATA state.
The output of the tokenisation step is a series of zero or more of the following tokens: DOCTYPE, start tag, end tag, comment, character, end-of-file. DOCTYPE tokens have names and can be either correct or in error. Start and end tag tokens have a tagname and a list of attributes, each of which has a name and a value. Comment and character tokens have data.
When a token is emitted, it must immediately be handled by the tree construction stage. The tree construction stage can affect the state of the content model flag, and can insert additional characters into the stream. (For example, the script
element can result in scripts executing and using the dynamic markup insertion APIs to insert characters into the stream being tokenised.)
Before each step of the tokeniser, the user agent must check to see if any scripts are ready. ...
Consume the next input character:
(This cannot happen if the content model flag is set to the CDATA state.)
Attempt to consume an entity.
If nothing is returned, emit a U+0026 AMPERSAND character token.
Otherwise, emit the character token that was returned.
Finally, switch to the data state.
The behaviour of this state depends on the content model flag.
If the next input character is a U+002F SOLIDUS (/) character, consume it and switch to the close tag open state. If the next input character is not a U+002F SOLIDUS (/) character, emit a U+003C LESS-THAN SIGN character token and reconsume the current input character in the data state.
Consume the next input character:
If the content model flag is set to the RCDATA or CDATA states then examine the next few characters. If they do not match the tag name of the last start tag token emitted (case insensitively), or if they do but they are not immediately followed by one of the following characters:
...then there is a parse error. Emit a U+003C LESS-THAN SIGN character token, a U+002F SOLIDUS character token, and reconsume the current input character in the data state.
Otherwise, if the content model flag is set to the PCDATA state, or if the next few characters do match that tag name, consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
When the user agent leaves the attribute name state (and before emitting the tag token, if appropriate), the complete attribute's name must be compared to the other attributes on the same token; if there is already an attribute on the token with the exact same name, then this is a parse error and the new attribute must be dropped, along with the value that gets associated with it (if any).
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Attempt to consume an entity.
If nothing is returned, append a U+0026 AMPERSAND character to the current attribute's value.
Otherwise, append the returned character token to the current attribute's value.
Finally, switch back to the attribute value state that you were in when were switched into this state.
(This can only happen if the content model flag is set to the PCDATA state.)
Consume every character up to the first U+003E GREATER-THAN SIGN character (AMPERSANDgt;) or the end of the file (EOF), whichever comes first. Emit a comment token whose data is the concatenation of all the characters starting from and including the character that caused the state machine to switch into the bogus comment state, up to and including the last consumed character before the U+003E character, if any, or up to the end of the file otherwise. (If the comment was started by the end of the file (EOF), the token is empty.)
Switch to the data state.
If the end of the file was reached, reconsume the EOF character.
(This can only happen if the content model flag is set to the PCDATA state.)
If the next two characters are both U+002D HYPHEN-MINUS (-) characters, consume those two characters, create a comment token whose data is the empty string, and switch to the comment state.
Otherwise if the next seven chacacters are a case-insensitive match for the word "DOCTYPE", then consume those characters and switch to the DOCTYPE state.
Otherwise, is is a parse error. Switch to the bogus comment state. The next character that is consumed, if any, is the first character that will be in the comment.
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
Consume the next input character:
First, consume the next input character:
Then, if the name of the DOCTYPE token is exactly the four letters "HTML", then mark the token as being correct. Otherwise, mark it as being in error.
Because lowercase letters in the name are uppercased by the algorithm above, the "HTML" letters are actually case-insensitive relative to the markup.
Consume the next input character:
Consume the next input character:
When an end tag token is emitted, the content model flag must be switched to the PCDATA state.
When an end tag token is emitted with attributes, that is a parse error.
A permitted slash is a U+002F SOLIDUS character that is immediately followed by a U+003E GREATER-THAN SIGN, if, and only if, the current token being processed is a start tag token whose tag name is one of the following: base
, link
, meta
, hr
, br
, img
, embed
, param
, area
, col
, input
This section defines how to consume an entity. This definition is used when parsing entities in text and in attributes.
The behaviour depends on the identity of the next character (the one immediately after the U+0026 AMPERSAND character):
Consume the U+0023 NUMBER SIGN.
The behaviour further depends on the character after the U+0023 NUMBER SIGN:
Consume the X.
Follow the steps below, but using the range of characters U+0030 DIGIT ZERO through to U+0039 DIGIT NINE, U+0061 LATIN SMALL LETTER A through to U+0078 LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER A, through to U+0058 LATIN CAPITAL LETTER F (in other words, 0-9, A-F, a-f).
When it comes to interpreting the number, interpret it as a hexadecimal number.
Follow the steps below, but using the range of characters U+0030 DIGIT ZERO through to U+0039 DIGIT NINE (i.e. just 0-9).
When it comes to interpreting the number, interpret it as a decimal number.
Consume as many characters as match the range of characters given above.
If no characters match the range, then don't consume any characters (and unconsume the U+0023 NUMBER SIGN character and, if appropriate, the X character). This is a parse error; nothing is returned.
Otherwise, if the next character is a U+003B SEMICOLON, consume that too. If it isn't, there is a parse error.
If one or more characters match the range, then take them all and interpret the string of characters as a number (either hexadecimal or decimal as appropriate), and return a character token for the Unicode character whose code point is that number. If the number is not a valid Unicode character (e.g. if the number is higher than 1114111), or if the number is zero, then return a character token for the U+FFFD REPLACEMENT CHARACTER character instead.
Consume the maximum number of characters possible, with the consumed characters case-sensitively matching one of the identifiers in the first column of the entities table.
If no match can be made, then this is a parse error. No characters are consumed, and nothing is returned.
Otherwise, if the next character is a U+003B SEMICOLON, consume that too. If it isn't, there is a parse error.
Return a character token for the character corresponding to the entity name (as given by the second column of the entities table).
If the markup contains I'm AMPERSANDamp;notit without you
, the entity is parsed as "not", as in, I'm AMPERSANDnot;it without you
. But if the markup was I'm AMPERSANDamp;notin without you
, the entity would be parsed as "notin", resulting in I'm AMPERSANDnotin; without you
.
This isn't quite right. For some entities, UAs require a semicolon, for others they don't. We probably need to do the same for backwards compatibility. If we do that we might be able to add more entities, e.g. for mathematics. Probably the way to mark whether or not an entity requires a semicolon is with an additional column in the entity table lower down.
The input to the tree construction stage is a sequence of tokens from the tokenisation stage. The tree construction stage is associated with a DOM Document
object when a parser is created. The "output" of this stage consists of dynamically modifying or extending that document's DOM tree.
Tree construction passes through several phases. Initially, UAs must act according to the steps described as being those of the initial phase.
This specification does not define when an interactive user agent has to render the Document
available to the user, or when it has to begin accepting user input.
When the steps below require the UA to append a character to a node, the UA must collect it and all subsequent consecutive characters that would be appended to that node, and insert one Text
node whose data is the concatenation of all those characters.
DOM mutation events must not fire for changes caused by the UA parsing the document. (Conceptually, the parser is not mutating the DOM, it is constructing it.) This includes the parsing of any content inserted using document.write()
and document.writeln()
calls. [DOM3EVENTS]
Not all of the tag names mentioned below are conformant tag names in this specification; many are included to handle legacy content. They still form part of the algorithm that implementations are required to implement to claim conformance.
The algorithm described below places no limit on the depth of the DOM tree generated, or on the length of tag names, attribute names, attribute values, text nodes, etc. While implementators are encouraged to avoid arbitrary limits, it is recognised that practical concerns will likely force user agents to impose nesting depths.
Initially, the tree construction stage must handle each token emitted from the tokenisation stage as follows:
This specification does not define how to handle this case. In particular, user agents may ignore the entirety of this specification altogether for such documents, and instead invoke special parse modes with a greater emphasis on backwards compatibility.
Browsers in particular have generally used DOCTYPE-based sniffing to invoke an "alternative conformance mode" known as quirks mode on certain documents. In this mode, emphasis is put on legacy compatibility rather than on standards compliance. This specification takes no position on this behaviour; documents without DOCTYPEs or with DOCTYPEs that do not conform to the syntax allowed by this specification are considered to be out of scope of this specification.
As far as parsing goes, the quirks I know of are:
AMPERSANDlt;script>AMPERSANDlt;!-- document.write('AMPERSANDlt;/script>'); -->AMPERSANDlt;/script>
AMPERSANDlt;/br>
and AMPERSANDlt;/p>
do magical things. p
can contain table
Maybe we should just adopt all those and be done with it. One parsing mode to rule them all. Or legitimise/codify the quirks mode parsing in some way.
Would be interesting to do a search to see how many pages hit each of the above.
Append a DocumentType
node to the Document
node, with the name
attribute set to the name given in the DOCTYPE token (which will be "HTML"), and the other attributes specific to DocumentType
objects set to null, empty lists, or the empty string as appropriate.
Then, switch to the root element phase of the tree construction stage.
Append that character to the Document
node.
After the initial phase, as each token is emitted from the tokenisation stage, it must be processed as described in this section.
Parse error. Ignore the token.
Append a Comment
node to the Document
object with the data
attribute set to the data given in the comment token.
Append that character to the Document
node.
Create an HTMLElement
node with the tag name html
, in the HTML namespace. Append it to the Document
object. Switch to the main phase and reprocess the current token.
Should probably make end tags be ignored, so that "AMPERSANDlt;/head>AMPERSANDlt;!-- -->AMPERSANDlt;html>" puts the comment befor the root node (or should we?)
The root element can end up being removed from the Document
object, e.g. by scripts; nothing in particular happens in such cases, content continues being appended to the nodes as described in the next section.
After the root element phase, each token emitted from the tokenisation stage must be processed as described in this section. This is by far the most involved part of parsing an HTML document.
The tree construction stage in this phase has several pieces of state: a stack of open elements, a list of active formatting elements, a head
element pointer, a form
element pointer, and an insertion mode.
We could just fold insertion modes and phases into one concept (and duplicate the two rules common to all insertion modes into all of them).
Initially the stack of open elements contains just the html
root element node created in the last phase before switching to this phase (or, in the innerHTML
case, the html
element created to represent the element whose innerHTML
attribute is being set). That's the topmost node of the stack. It never gets popped off the stack. (This stack grows downwards.)
The current node is the bottommost node in this stack.
Elements in the stack fall into the following categories:
The following HTML elements have varying levels of special parsing rules: address
, area
, base
, basefont
, bgsound
, blockquote
, body
, br
, center
, col
, colgroup
, dd
, dir
, div
, dl
, dt
, embed
, fieldset
, form
, frame
, frameset
, h1
, h2
, h3
, h4
, h5
, h6
, head
, hr
, iframe
, image
, img
, input
, isindex
, li
, link
, listing
, menu
, meta
, noembed
, noframes
, noscript
, ol
, optgroup
, option
, p
, param
, plaintext
, pre
, script
, select
, spacer
, style
, tbody
, textarea
, tfoot
, thead
, title
, tr
, ul
, and wbr
.
The following HTML elements introduce new scopes for various parts of the parsing: button
, caption
, html
, marquee
, object
, table
, td
and th
.
The following HTML elements are those that end up in the list of active formatting elements: a
, b
, big
, em
, font
, i
, nobr
, s
, small
, strike
, strong
, tt
, and u
.
All other elements found while parsing an HTML document.
Still need to add these new elements to the lists: event-source
, section
, nav
, article
, aside
, header
, footer
, datagrid
, command
The stack of open elements is said to have an element in scope or have an element in table scope when the following algorithm terminates in a match state:
Initialise node to be the current node (the bottommost node of the stack).
If node is the target node, terminate in a match state.
Otherwise, if node is a table
element, terminate in a failure state.
Otherwise, if the algorithm is the "has an element in scope" variant (rather than the "has an element in table scope" variant), and node is one of the following, terminate in a failure state:
Otherwise, if node is an html
element, terminate in a failure state. (This can only happen if the node is the topmost node of the stack of open elements, and prevents the next step from being invoked if there are no more elements in the stack.)
Otherwise, set node to the previous entry in the stack of open elements and return to step 2. (This will never fail, since the loop will always terminate in the previous step if the top of the stack is reached.)
Nothing happens if at any time any of the elements in the stack of open elements are moved to a new location in, or removed from, the Document
tree. In particular, the stack is not changed in this situation. This can cause, amongst other strange effects, content to be appended to nodes that are no longer in the DOM.
In some cases (namely, when closing misnested formatting elements), the stack is manipulated in a random-access fashion.
Initially the list of active formatting elements is empty. It is used to handle mis-nested formatting element tags.
The list contains elements in the formatting category, and scope markers. The scope markers are inserted when entering buttons, object
elements, marquees, table cells, and table captions, and are used to prevent formatting from "leaking" into tables, buttons, object
elements, and marquees.
When the steps below require the UA to reconstruct the active formatting elements, the UA must perform the following steps:
This has the effect of reopening all the formatting elements that were opened in the current body, cell, or caption (whichever is youngest) that haven't been explicitly closed.
The way this specification is written, the list of active formatting elements always consists of elements in chronological order with the least recently added element first and the most recently added element last (except for while steps 8 to 11 of the above algorithm are being executed, of course).
When the steps below require the UA to clear the list of active formatting elements up to the last marker, the UA must perform the following steps:
When the steps below require the UA to create an element for a token, the UA must create a node implementing the interface appropriate for the element type corresponding to the tag name of the token (as given in the section of this specification that defines that element, e.g. for an a
element it would be the HTMLAnchorElement
interface), with the tag name being the name of that element, with the node being in the HTML namespace, and with the attributes on the node being those given in the given token.
When the steps below require the UA to insert an HTML element for a token, the UA must first create an element for the token, and then append this node to the current node, and push it onto the stack of open elements so that it is the new current node.
The steps below may also require that the UA insert an HTML element in a particular place, in which case the UA must create an element for the token and then insert or append the new node in the location specified. (This happens in particular during the parsing of tables with invalid content.)
The interface appropriate for an element that is not defined in this specification is HTMLElement
.
When the steps below require the UA to generate implied end tags, then, if the current node is a dd
element, a dt
element, an li
element, a p
element, a td
element, a th
element, or a tr
element, the UA must act as if an end tag with the respective tag name had been seen and then generate implied end tags again.
The step that requires the UA to generate implied end tags but lists an element to exclude from the process, then the UA must perform the above steps as if that element was not in the above list.
Initially the head
element pointer and the form
element pointer are both null.
Once a head
element has been parsed (whether implicitly or explicitly) the head
element pointer gets set to point to this node.
The form
element pointer points to the last form
element that was opened and whose end tag has not yet been seen. It is used to make form controls associate with forms in the face of dramatically bad markup, for historical reasons.
Initially the insertion mode is "before head". It can change to "in head", "after head", "in body", "in table", "in caption", "in column group", "in table body", "in row", "in cell", "in select", "after body", "in frameset", and "after frameset" during the course of the parsing, as described below. It affects how certain tokens are processed.
If the tree construction stage is switched from the main phase to the trailing end phase and back again, the various pieces of state are not reset; the UA must act as if the state was maintained.
When the steps below require the UA to reset the insertion mode appropriately, it means the UA must follow these steps:
innerHTML
attribute is being set is neither a td
element nor a th
element, then set node to the element whose innerHTML
attribute is being set. (innerHTML
case) select
element, then switch the insertion mode to "in select" and abort these steps. (innerHTML
case) td
or th
element, then switch the insertion mode to "in cell" and abort these steps. tr
element, then switch the insertion mode to "in row" and abort these steps. tbody
, thead
, or tfoot
element, then switch the insertion mode to "in table body" and abort these steps. caption
element, then switch the insertion mode to "in caption" and abort these steps. colgroup
element, then switch the insertion mode to "in column group" and abort these steps. (innerHTML
case) table
element, then switch the insertion mode to "in table" and abort these steps. head
element, then switch the insertion mode to "in body" ("in body"! not "in head"!) and abort these steps. (innerHTML
case) body
element, then switch the insertion mode to "in body" and abort these steps. frameset
element, then switch the insertion mode to "in frameset" and abort these steps. (innerHTML
case) html
element, then: if the head
element pointer is null, switch the insertion mode to "before head", otherwise, switch the insertion mode to "after head". In either case, abort these steps. (innerHTML
case)innerHTML
case) Tokens in the main phase must be handled as follows:
Parse error. Ignore the token.
If this start tag token was not the first start tag token, then it is a parse error.
For each attribute on the token, check to see if the attribute is already present on the top element of the stack of open elements. If it is not, add the attribute and its corresponding value to that element.
If there's more than one node on the stack of open elements, or, if the parser was not originally created in order to handle the setting of an element's innerHTML
attribute (innerHTML
case) and the second node on the stack of open elements is not a body
node, this is a parse error.
This fails because it doesn't imply HEAD and BODY tags. We should probably expand out the insertion modes and merge them with phases and then put the three things here into each insertion mode instead of trying to factor them out so carefully.
Depends on the insertion mode:
Handle the token as follows:
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Create an element for the token.
Set the head
element pointer to this new element node.
Append the new element to the current node and push it onto the stack of open elements.
Change the insertion mode to "in head".
Act as if a start tag token with the tag name "head" and no attributes had been seen, then reprocess the current token.
This will result in a head
element being generated, and with the current token being reprocessed in the "in head" insertion mode.
Act as if a start tag token with the tag name "head" and no attributes had been seen, then reprocess the current token.
Parse error. Ignore the token.
Act as if a start tag token with the tag name "head" and no attributes had been seen, then reprocess the current token.
This will result in an empty head
element being generated, with the current token being reprocessed in the "after head" insertion mode.
Handle the token as follows.
The rules for handling "title", "style", and "script" start tags are similar, but not identical.
It is possible for the tree construction stage's main phase to be in the "in head" insertion mode without the current node being a head
element, e.g. if a head
end tag is immediately followed by a meta
start tag.
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Create an element for the token.
Append the new element to the node pointed to by the head
element pointer, or, if that is null (innerHTML
case), to the current node.
Switch the tokeniser's content model flag to the RCDATA state.
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token.
If this process resulted in a collection of character tokens, append a single Text
node to the title
element node whose contents is the concatenation of all those tokens' characters.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is an end tag token with the tag name "title", ignore it. Otherwise, this is a parse error.
Create an element for the token.
Append the new element to the node pointed to by the head
element pointer, or, if that is null (innerHTML
case), to the current node.
Switch the tokeniser's content model flag to the CDATA state.
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token, or until it stops tokenising.
If this process resulted in a collection of character tokens, append a single Text
node to the style
element node whose contents is the concatenation of all those tokens' characters.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is an end tag token with the tag name "style", ignore it. Otherwise, this is a parse error.
Create an element for the token.
Mark the element as being "parser-inserted". This ensures that, if the script is external, any document.write()
calls in the script will execute in-line, instead of blowing the document away, as would happen in most other cases.
Switch the tokeniser's content model flag to the CDATA state.
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token, or until it stops tokenising.
If this process resulted in a collection of character tokens, append a single Text
node to the script
element node whose contents is the concatenation of all those tokens' characters.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is not an end tag token with the tag name "script", then this is a parse error; mark the script
element as "already executed". Otherwise, the token is the script
element's end tag, so ignore it.
If the parser was originally created in order to handle the setting of a node's innerHTML
attribute, then mark the script
element as "already executed", and skip the rest of the processing described for this token (including the part below where "scripts that will execute as soon as the parser resumes" are executed). (innerHTML
case)
Marking the script
element as "already executed" prevents it from executing when it is inserted into the document a few paragraphs below. Scripts missing their end tags and scripts that were inserted using innerHTML
aren't executed.
Let the old insertion point have the same value as the current insertion point. Let the insertion point be just before the next input character.
Append the new element to the current node, unless the insertion mode is "in head" and the head
element pointer is not null, in which case append it to the node pointed to by the head
element pointer. Special processing occurs when a script
element is inserted into a document that might cause some script to execute, which might cause new characters to be inserted into the tokeniser.
Let the insertion point have the value of the old insertion point. (In other words, restore the insertion point to the value it had before the previous paragraph. This value might be the "undefined" value.)
At this stage, if there is a script that will execute as soon as the parser resumes, then:
document.write()
: Abort the processing of any nested invokations of the tokeniser, yielding control back to the caller. (Tokenisation will resume when the caller returns to the "outer" tree construction stage.)
Follow these steps:
Let the script be the script that will execute as soon as the parser resumes. There is no longer a script that will execute as soon as the parser resumes.
Pause until the script has completed loading.
Let the insertion point be just before the next input character.
Let the insertion point be undefined again.
If there is once again a script that will execute as soon as the parser resumes, then repeat these steps from step 1.
Create an element for the token.
Append the new element to the node pointed to by the head
element pointer, or, if that is null (innerHTML
case), to the current node.
Need to cope with second and subsequent base
elements affecting subsequent elements magically.
If the current node is a head
element, pop the current node off the stack of open elements. Otherwise, this is a parse error.
Change the insertion mode to "after head".
Act as described in the "anything else" entry below.
Parse error. Ignore the token.
If the current node is a head
element, act as if an end tag token with the tag name "head" had been seen.
Otherwise, change the insertion mode to "after head".
Then, reprocess the current token.
In certain UAs, some elements don't trigger the "in body" mode straight away, but instead get put into the head. Do we want to copy that?
Handle the token as follows:
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Insert a body
element for the token.
Change the insertion mode to "in body".
Insert a frameset
element for the token.
Change the insertion mode to "in frameset".
Parse error. Switch the insertion mode back to "in head" and reprocess the token.
Act as if a start tag token with the tag name "body" and no attributes had been seen, and then reprocess the current token.
Handle the token as follows:
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Process the token as if the insertion mode had been "in head".
Parse error. Process the token as if the insertion mode had been "in head".
If the second element on the stack of open elements is not a body
element, or, if the stack of open elements has only one node on it, then ignore the token. (innerHTML
case)
Otherwise, for each attribute on the token, check to see if the attribute is already present on the body
element (the second element) on the stack of open elements. If it is not, add the attribute and its corresponding value to that element.
If the second element in the stack of open elements is not a body
element, this is a parse error. Ignore the token. (innerHTML
case)
Otherwise:
If the current node is not the body
element, then this is a parse error.
Change the insertion mode to "after body".
Act as if an end tag with tag name "body" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the innerHTML
case.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
Insert an HTML element for the token.
If the form
element pointer is not null, ignore the token with a parse error.
Otherwise:
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
Insert an HTML element for the token, and set the form
element pointer to point to the element created.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
Run the following algorithm:
Initialise node to be the current node (the bottommost node of the stack).
If node is an li
element, then pop all the nodes from the current node up to node, including node, then stop this algorithm.
If node is not in the formatting category, and is not in the phrasing category, and is not an address
or div
element, then stop this algorithm.
Otherwise, set node to the previous entry in the stack of open elements and return to step 2.
Finally, insert an li
element.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
Run the following algorithm:
Initialise node to be the current node (the bottommost node of the stack).
If node is a dd
or dt
element, then pop all the nodes from the current node up to node, including node, then stop this algorithm.
If node is not in the formatting category, and is not in the phrasing category, and is not an address
or div
element, then stop this algorithm.
Otherwise, set node to the previous entry in the stack of open elements and return to step 2.
Finally, insert an HTML element with the same tag name as the token's.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
Insert an HTML element for the token.
Switch the content model flag to the PLAINTEXT state.
Once a start tag with the tag name "plaintext" has been seen, that will be the last token ever seen other than character tokens (and the end-of-file token), because there is no way to switch the content model flag out of the PLAINTEXT state.
If the stack of open elements has an element in scope with the same tag name as that of the token, then generate implied end tags.
Now, if the current node is not an element with the same tag name as that of the token, then this is a parse error.
If the stack of open elements has an element in scope with the same tag name as that of the token, then pop elements from this stack until an element with that tag name has been popped from the stack.
If the stack of open elements has an element in scope with the same tag name as that of the token, then generate implied end tags.
Now, if the current node is not an element with the same tag name as that of the token, then this is a parse error.
If the stack of open elements has an element in scope with the same tag name as that of the token, then pop elements from this stack until an element with that tag name has been popped from the stack.
In any case, set the form
element pointer to null.
If the stack of open elements has a p
element in scope, then generate implied end tags, except for p
elements.
If the current node is not a p
element, then this is a parse error.
If the stack of open elements has a p
element in scope, then pop elements from this stack until the stack no longer has a p
element in scope.
If the stack of open elements has an element in scope whose tag name matches the tag name of the token, then generate implied end tags, except for elements with the same tag name as the token.
If the current node is not an element with the same tag name as the token, then this is a parse error.
If the stack of open elements has an element in scope whose tag name matches the tag name of the token, then pop elements from this stack until an element with that tag name has been popped from the stack.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
If the stack of open elements has in scope an element whose tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then this is a parse error; pop elements from the stack until an element with one of those tag names has been popped from the stack.
Insert an HTML element for the token.
If the stack of open elements has in scope an element whose tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then generate implied end tags.
Now, if the current node is not an element with the same tag name as that of the token, then this is a parse error.
If the stack of open elements has in scope an element whose tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then pop elements from the stack until an element with one of those tag names has been popped from the stack.
If the list of active formatting elements contains an element whose tag name is "a" between the end of the list and the last marker on the list (or the start of the list if there is no marker on the list), then this is a parse error; act as if an end tag with the tag name "a" had been seen, then remove that element from the list of active formatting elements and the stack of open elements if the end tag didn't already remove it (it might not have if the element is not in table scope).
In the non-conforming stream AMPERSANDlt;aAMPERSANDnbsp;href="a">aAMPERSANDlt;table>AMPERSANDlt;aAMPERSANDnbsp;href="b">bAMPERSANDlt;/table>x
, the first a
element would be closed upon seeing the second one, and the "x" character would be inside a link to "b", not to "a". This is despite the fact that the outer a
element is not in table scope (meaning that a regular AMPERSANDlt;/a>
end tag at the start of the table wouldn't close the outer a
element).
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token. Add that element to the list of active formatting elements.
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token. Add that element to the list of active formatting elements.
Follow these steps:
Let the formatting element be the last element in the list of active formatting elements that:
If there is no such node, or, if that node is also in the stack of open elements but the element is not in scope, then this is a parse error. Abort these steps. The token is ignored.
Otherwise, if there is such a node, but that node is not in the stack of open elements, then this is a parse error; remove the element from the list, and abort these steps.
Otherwise, there is a formatting element and that element is in the stack and is in scope. If the element is not the current node, this is a parse error. In any case, proceed with the algorithm as written in the following steps.
Let the furthest block be the topmost node in the stack of open elements that is lower in the stack than the formatting element, and is not an element in the phrasing or formatting categories. There might not be one.
If there is no furthest block, then the UA must skip the subsequent steps and instead just pop all the nodes from the bottom of the stack of open elements, from the current node up to the formatting element, and remove the formatting element from the list of active formatting elements.
Let the common ancestor be the element immediately above the formatting element in the stack of open elements.
If the furthest block has a parent node, then remove the furthest block from its parent node.
Let a bookmark note the position of the formatting element in the list of active formatting elements relative to the elements on either side of it in the list.
Let node and last node be the furthest block. Follow these steps:
Insert whatever last node ended up being in the previous step into the common ancestor node, first removing it from its previous parent node if any.
Perform a shallow clone of the formatting element.
Take all of the child nodes of the furthest block and append them to the clone created in the last step.
Append that clone to the furthest block.
Remove the formatting element from the list of active formatting elements, and insert the clone into the list of active formatting elements at the position of the aforementioned bookmark.
Remove the formatting element from the stack of open elements, and insert the clone into the stack of open elements immediately after (i.e. in a more deeply nested position than) the position of the furthest block in that stack.
Jump back to step 1 in this series of steps.
The way these steps are defined, only elements in the formatting category ever get cloned by this algorithm.
Because of the way this algorithm causes elements to change parents, it has been dubbed the "adoption agency algorithm" (in contrast with other possibly algorithms for dealing with misnested content, which included the "incest algorithm", the "secret affair algorithm", and the "Heisenberg algorithm").
If the stack of open elements has a button
element in scope, then this is a parse error; act as if an end tag with the tag name "button" had been seen, then reprocess the token.
Otherwise:
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
Insert a marker at the end of the list of active formatting elements.
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
Insert a marker at the end of the list of active formatting elements.
If the stack of open elements has in scope an element whose tag name is the same as the tag name of the token, then generate implied end tags.
Now, if the current node is not an element with the same tag name as the token, then this is a parse error.
Now, if the stack of open elements has an element in scope whose tag name matches the tag name of the token, then pop elements from the stack until that element has been popped from the stack, and clear the list of active formatting elements up to the last marker.
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
Switch the content model flag to the CDATA state.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
Insert an HTML element for the token.
Change the insertion mode to "in table".
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
If the stack of open elements has a p
element in scope, then act as if an end tag with the tag name p
had been seen.
Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
Parse error. Change the token's tag name to "img" and reprocess it. (Don't ask.)
Reconstruct the active formatting elements, if any.
Insert an input
element for the token.
If the form
element pointer is not null, then associate the input
element with the form
element pointed to by the form
element pointer.
Pop that input
element off the stack of open elements.
If the form
element pointer is not null, then ignore the token.
Otherwise:
Act as if a start tag token with the tag name "form" had been seen.
Act as if a start tag token with the tag name "hr" had been seen.
Act as if a start tag token with the tag name "p" had been seen.
Act as if a start tag token with the tag name "label" had been seen.
Act as if a stream of character tokens had been seen (see below for what they should say).
Act as if a start tag token with the tag name "input" had been seen, with all the attributes from the "isindex" token, except with the "name" attribute set to the value "isindex" (ignoring any explicit "name" attribute).
Act as if a stream of character tokens had been seen (see below for what they should say).
Act as if an end tag token with the tag name "label" had been seen.
Act as if an end tag token with the tag name "p" had been seen.
Act as if a start tag token with the tag name "hr" had been seen.
Act as if an end tag token with the tag name "form" had been seen.
The two streams of character tokens together should, together with the input
element, express the equivalent of "This is a searchable index. Insert your search keywords here: (input field)" in the user's preferred language.
Then need to specify that if the form submission causes just a single form control, whose name is "isindex", to be submitted, then we submit just the value part, not the "isindex=" part.
Create an element for the token.
If the form
element pointer is not null, then associate the textarea
element with the form
element pointed to by the form
element pointer.
Append the new element to the current node.
Switch the tokeniser's content model flag to the RCDATA state.
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token, or until it stops tokenising.
If this process resulted in a collection of character tokens, append a single Text
node, whose contents is the concatenation of all those tokens' characters, to the new element node.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is an end tag token with the tag name "textarea", ignore it.
Create an element for the token.
For "iframe" tags, the node must be an HTMLIFrameElement
object, for the other tags it must be an HTMLElement
object.
Append the new element to the current node.
Switch the tokeniser's content model flag to the CDATA state.
Then, collect all the character tokens that the tokeniser returns until it returns a token that is not a character token, or until it stops tokenising.
If this process resulted in a collection of character tokens, append a single Text
node, whose contents is the concatenation of all those tokens' characters, to the new element node.
The tokeniser's content model flag will have switched back to the PCDATA state.
If the next token is an end tag token with the same tag name as the start tag token, ignore it.
Need something here for when scripting is disabled.
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
Change the insertion mode to "in select".
Parse error. Ignore the token.
Work in progress!
Reconstruct the active formatting elements, if any.
Insert an HTML element for the token.
This element will be a phrasing element.
Run the following algorithm:
Initialise node to be the current node (the bottommost node of the stack).
If node has the same tag name as the end tag token, then:
If the tag name of the end tag token does not match the tag name of the current node, this is a parse error.
Pop all the nodes from the current node up to node, including node, then stop this algorithm.
Otherwise, if node is in neither the formatting category nor the phrasing category, then this is a parse error. Stop this algorithm. The end tag token is ignored.
Set node to the previous entry in the stack of open elements.
Return to step 2.
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Clear the stack back to a table context. (See below.)
Insert a marker at the end of the list of active formatting elements.
Insert an HTML element for the token, then switch the insertion mode to "in caption".
Clear the stack back to a table context. (See below.)
Insert an HTML element for the token, then switch the insertion mode to "in column group".
Act as if a start tag token with the tag name "colgroup" had been seen, then reprocess the current token.
Clear the stack back to a table context. (See below.)
Insert an HTML element for the token, then switch the insertion mode to "in table body".
Act as if a start tag token with the tag name "tbody" had been seen, then reprocess the current token.
Parse error. Act as if an end tag token with the tag name "table" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the innerHTML
case.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token. (innerHTML
case)
Otherwise:
Now, if the current node is not a table
element, then this is a parse error.
Pop elements from this stack until a table
element has been popped from the stack.
Parse error. Ignore the token.
Parse error. Process the token as if the insertion mode was "in body", with the following exception:
If the current node is a table
, tbody
, tfoot
, thead
, or tr
element, then, whenever a node would be inserted into the current node, it must instead be inserted into the foster parent element.
The foster parent element is the parent element of the last table
element in the stack of open elements, if there is a table
element and it has such a parent element. If there is no table
element in the stack of open elements (innerHTML
case), then the foster parent element is the first element in the stack of open elements (the html
element). Otherwise, if there is a table
element in the stack of open elements, but the last table
element in the stack of open elements has no parent, or its parent node is not an element, then the foster parent element is the element before the last table
element in the stack of open elements.
If the foster parent element is the parent element of the last table
element in the stack of open elements, then the new node must be inserted immediately before the last table
element in the stack of open elements in the foster parent element; otherwise, the new node must be appended to the foster parent element.
When the steps above require the UA to clear the stack back to a table context, it means that the UA must, while the current node is not a table
element or an html
element, pop elements from the stack of open elements. If this causes any elements to be popped from the stack, then this is a parse error.
The current node being an html
element after this process is an innerHTML
case.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token. (innerHTML
case)
Otherwise:
Now, if the current node is not a caption
element, then this is a parse error.
Pop elements from this stack until a caption
element has been popped from the stack.
Clear the list of active formatting elements up to the last marker.
Switch the insertion mode to "in table".
Parse error. Act as if an end tag with the tag name "caption" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the innerHTML
case.
Parse error. Ignore the token.
Process the token as if the insertion mode was "in body".
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Insert a col
element for the token. Immediately pop the current node off the stack of open elements.
If the current node is the root html
element, then this is a parse error, ignore the token. (innerHTML
case)
Otherwise, pop the current node (which will be a colgroup
element) from the stack of open elements. Switch the insertion mode to "in table".
Parse error. Ignore the token.
Act as if an end tag with the tag name "colgroup" had been seen, and then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the innerHTML
case.
Clear the stack back to a table body context. (See below.)
Insert a tr
element for the token, then switch the insertion mode to "in row".
Parse error. Act as if a start tag with the tag name "tr" had been seen, then reprocess the current token.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token.
Otherwise:
Clear the stack back to a table body context. (See below.)
Pop the current node from the stack of open elements. Switch the insertion mode to "in table".
If the stack of open elements does not have a tbody
, thead
, or tfoot
element in table scope, this is a parse error. Ignore the token. (innerHTML
case)
Otherwise:
Clear the stack back to a table body context. (See below.)
Act as if an end tag with the same tag name as the current node ("tbody", "tfoot", or "thead") had been seen, then reprocess the current token.
Parse error. Ignore the token.
Process the token as if the insertion mode was "in table".
When the steps above require the UA to clear the stack back to a table body context, it means that the UA must, while the current node is not a tbody
, tfoot
, thead
, or html
element, pop elements from the stack of open elements. If this causes any elements to be popped from the stack, then this is a parse error.
The current node being an html
element after this process is an innerHTML
case.
Clear the stack back to a table row context. (See below.)
Insert an HTML element for the token, then switch the insertion mode to "in cell".
Insert a marker at the end of the list of active formatting elements.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token. (innerHTML
case)
Otherwise:
Clear the stack back to a table row context. (See below.)
Pop the current node (which will be a tr
element) from the stack of open elements. Switch the insertion mode to "in table body".
Act as if an end tag with the tag name "tr" had been seen, then, if that token wasn't ignored, reprocess the current token.
The fake end tag token here can only be ignored in the innerHTML
case.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token.
Otherwise, act as if an end tag with the tag name "tr" had been seen, then reprocess the current token.
Parse error. Ignore the token.
Process the token as if the insertion mode was "in table".
When the steps above require the UA to clear the stack back to a table row context, it means that the UA must, while the current node is not a tr
element or an html
element, pop elements from the stack of open elements. If this causes any elements to be popped from the stack, then this is a parse error.
The current node being an html
element after this process is an innerHTML
case.
If the stack of open elements does not have an element in table scope with the same tag name as that of the token, then this is a parse error and the token must be ignored.
Otherwise:
Generate implied end tags, except for elements with the same tag name as the token.
Now, if the current node is not an element with the same tag name as the token, then this is a parse error.
Pop elements from this stack until an element with the same tag name as the token has been popped from the stack.
Clear the list of active formatting elements up to the last marker.
Switch the insertion mode to "in row". (The current node will be a tr
element at this point.)
If the stack of open elements does not have a td
or th
element in table scope, then this is a parse error; ignore the token. (innerHTML
case)
Otherwise, close the cell (see below) and reprocess the current token.
Parse error. Ignore the token.
If the stack of open elements does not have an element in table scope with the same tag name as that of the token (which can only happen for "tbody", "tfoot" and "thead", or, in the innerHTML
case), then this is a parse error and the token must be ignored.
Otherwise, close the cell (see below) and reprocess the current token.
Process the token as if the insertion mode was "in body".
Where the steps above say to close the cell, they mean to follow the following algorithm:
If the stack of open elements has a td
element in table scope, then act as if an end tag token with the tag name "td" had been seen.
Otherwise, the stack of open elements will have a th
element in table scope; act as if an end tag token with the tag name "th" had been seen.
The stack of open elements cannot have both a td
and a th
element in table scope at the same time, nor can it have neither when the insertion mode is "in cell".
Handle the token as follows:
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
If the current node is an option
element, act as if an end tag with the tag name "option" had been seen.
Insert an HTML element for the token.
If the current node is an option
element, act as if an end tag with the tag name "option" had been seen.
If the current node is an optgroup
element, act as if an end tag with the tag name "optgroup" had been seen.
Insert an HTML element for the token.
First, if the current node is an option
element, and the node immediately before it in the stack of open elements is an optgroup
element, then act as if an end tag with the tag name "option" had been seen.
If the current node is an optgroup
element, then pop that node from the stack of open elements. Otherwise, this is a parse error, ignore the token.
If the current node is an option
element, then pop that node from the stack of open elements. Otherwise, this is a parse error, ignore the token.
If the stack of open elements does not have an element in table scope with the same tag name as the token, this is a parse error. Ignore the token. (innerHTML
case)
Otherwise:
Pop elements from the stack of open elements until a select
element has been popped from the stack.
Parse error. Act as if the token had been an end tag with the tag name "select" instead.
If the stack of open elements has an element in table scope with the same tag name as that of the token, then act as if an end tag with the tag name "select" had been seen, and reprocess the token. Otherwise, ignore the token.
Parse error. Ignore the token.
Handle the token as follows:
Process the token as it would be processed if the insertion mode was "in body".
Append a Comment
node to the first element in the stack of open elements (the html
element), with the data
attribute set to the data given in the comment token.
If the parser was originally created in order to handle the setting of an element's innerHTML
attribute, this is a parse error; ignore the token. (The element will be an html
element in this case.) (innerHTML
case)
Otherwise, switch to the trailing end phase.
Parse error. Set the insertion mode to "in body" and reprocess the token.
Handle the token as follows:
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Insert a frameset
element for the token.
If the current node is the root html
element, then this is a parse error; ignore the token. (innerHTML
case)
Otherwise, pop the current node from the stack of open elements.
If the parser was not originally created in order to handle the setting of an element's innerHTML
attribute (innerHTML
case), and the current node is no longer a frameset
element, then change the insertion mode to "after frameset".
Insert an HTML element for the token. Immediately pop the current node off the stack of open elements.
Process the token as if the insertion mode had been "in body".
Parse error. Ignore the token.
Handle the token as follows:
Append the character to the current node.
Append a Comment
node to the current node with the data
attribute set to the data given in the comment token.
Switch to the trailing end phase.
Process the token as if the insertion mode had been "in body".
Parse error. Ignore the token.
This doesn't handle UAs that don't support frames, or that do support frames but want to show the NOFRAMES content. Supporting the former is easy; supporting the latter is harder.
After the main phase, as each token is emitted from the tokenisation stage, it must be processed as described in this section.
Parse error. Ignore the token.
Append a Comment
node to the Document
object with the data
attribute set to the data given in the comment token.
Process the token as it would be processed in the main phase.
Parse error. Switch back to the main phase and reprocess the token.
Need to define the term stop parsing. have to run all pending scripts (so document.write()s work) and say something about the load event. Also need to execute any pending loads of scripts in the "list of scripts that will execute when the document has finished parsing".
The HTML namespace is: http://www.w3.org/1999/xhtml
This table lists the entity names that are supported by HTML, and the code points to which they refer. It is referenced by the previous sections.
Entity Name | Character |
---|---|
AElig | U+00C6 |
Aacute | U+00C1 |
Acirc | U+00C2 |
Agrave | U+00C0 |
Alpha | U+0391 |
Aring | U+00C5 |
Atilde | U+00C3 |
Auml | U+00C4 |
Beta | U+0392 |
Ccedil | U+00C7 |
Chi | U+03A7 |
Dagger | U+2021 |
Delta | U+0394 |
ETH | U+00D0 |
Eacute | U+00C9 |
Ecirc | U+00CA |
Egrave | U+00C8 |
Epsilon | U+0395 |
Eta | U+0397 |
Euml | U+00CB |
Gamma | U+0393 |
Iacute | U+00CD |
Icirc | U+00CE |
Igrave | U+00CC |
Iota | U+0399 |
Iuml | U+00CF |
Kappa | U+039A |
Lambda | U+039B |
Mu | U+039C |
Ntilde | U+00D1 |
Nu | U+039D |
OElig | U+0152 |
Oacute | U+00D3 |
Ocirc | U+00D4 |
Ograve | U+00D2 |
Omega | U+03A9 |
Omicron | U+039F |
Oslash | U+00D8 |
Otilde | U+00D5 |
Ouml | U+00D6 |
Phi | U+03A6 |
Pi | U+03A0 |
Prime | U+2033 |
Psi | U+03A8 |
Rho | U+03A1 |
Scaron | U+0160 |
Sigma | U+03A3 |
THORN | U+00DE |
Tau | U+03A4 |
Theta | U+0398 |
Uacute | U+00DA |
Ucirc | U+00DB |
Ugrave | U+00D9 |
Upsilon | U+03A5 |
Uuml | U+00DC |
Xi | U+039E |
Yacute | U+00DD |
Yuml | U+0178 |
Zeta | U+0396 |
aacute | U+00E1 |
acirc | U+00E2 |
acute | U+00B4 |
aelig | U+00E6 |
agrave | U+00E0 |
alefsym | U+2135 |
alpha | U+03B1 |
amp | U+0026 |
AMP | U+0026 |
and | U+2227 |
ang | U+2220 |
apos | U+0027 |
aring | U+00E5 |
asymp | U+2248 |
atilde | U+00E3 |
auml | U+00E4 |
bdquo | U+201E |
beta | U+03B2 |
brvbar | U+00A6 |
bull | U+2022 |
cap | U+2229 |
ccedil | U+00E7 |
cedil | U+00B8 |
cent | U+00A2 |
chi | U+03C7 |
circ | U+02C6 |
clubs | U+2663 |
cong | U+2245 |
copy | U+00A9 |
COPY | U+00A9 |
crarr | U+21B5 |
cup | U+222A |
curren | U+00A4 |
dArr | U+21D3 |
dagger | U+2020 |
darr | U+2193 |
deg | U+00B0 |
delta | U+03B4 |
diams | U+2666 |
divide | U+00F7 |
eacute | U+00E9 |
ecirc | U+00EA |
egrave | U+00E8 |
empty | U+2205 |
emsp | U+2003 |
ensp | U+2002 |
epsilon | U+03B5 |
equiv | U+2261 |
eta | U+03B7 |
eth | U+00F0 |
euml | U+00EB |
euro | U+20AC |
exist | U+2203 |
fnof | U+0192 |
forall | U+2200 |
frac12 | U+00BD |
frac14 | U+00BC |
frac34 | U+00BE |
frasl | U+2044 |
gamma | U+03B3 |
ge | U+2265 |
gt | U+003E |
GT | U+003E |
hArr | U+21D4 |
harr | U+2194 |
hearts | U+2665 |
hellip | U+2026 |
iacute | U+00ED |
icirc | U+00EE |
iexcl | U+00A1 |
igrave | U+00EC |
image | U+2111 |
infin | U+221E |
int | U+222B |
iota | U+03B9 |
iquest | U+00BF |
isin | U+2208 |
iuml | U+00EF |
kappa | U+03BA |
lArr | U+21D0 |
lambda | U+03BB |
lang | U+2329 |
laquo | U+00AB |
larr | U+2190 |
lceil | U+2308 |
ldquo | U+201C |
le | U+2264 |
lfloor | U+230A |
lowast | U+2217 |
loz | U+25CA |
lrm | U+200E |
lsaquo | U+2039 |
lsquo | U+2018 |
lt | U+003C |
LT | U+003C |
macr | U+00AF |
mdash | U+2014 |
micro | U+00B5 |
middot | U+00B7 |
minus | U+2212 |
mu | U+03BC |
nabla | U+2207 |
nbsp | U+00A0 |
ndash | U+2013 |
ne | U+2260 |
ni | U+220B |
not | U+00AC |
notin | U+2209 |
nsub | U+2284 |
ntilde | U+00F1 |
nu | U+03BD |
oacute | U+00F3 |
ocirc | U+00F4 |
oelig | U+0153 |
ograve | U+00F2 |
oline | U+203E |
omega | U+03C9 |
omicron | U+03BF |
oplus | U+2295 |
or | U+2228 |
ordf | U+00AA |
ordm | U+00BA |
oslash | U+00F8 |
otilde | U+00F5 |
otimes | U+2297 |
ouml | U+00F6 |
para | U+00B6 |
part | U+2202 |
permil | U+2030 |
perp | U+22A5 |
phi | U+03C6 |
pi | U+03C0 |
piv | U+03D6 |
plusmn | U+00B1 |
pound | U+00A3 |
prime | U+2032 |
prod | U+220F |
prop | U+221D |
psi | U+03C8 |
quot | U+0022 |
QUOT | U+0022 |
rArr | U+21D2 |
radic | U+221A |
rang | U+232A |
raquo | U+00BB |
rarr | U+2192 |
rceil | U+2309 |
rdquo | U+201D |
real | U+211C |
reg | U+00AE |
REG | U+00AE |
rfloor | U+230B |
rho | U+03C1 |
rlm | U+200F |
rsaquo | U+203A |
rsquo | U+2019 |
sbquo | U+201A |
scaron | U+0161 |
sdot | U+22C5 |
sect | U+00A7 |
shy | U+00AD |
sigma | U+03C3 |
sigmaf | U+03C2 |
sim | U+223C |
spades | U+2660 |
sub | U+2282 |
sube | U+2286 |
sum | U+2211 |
sup | U+2283 |
sup1 | U+00B9 |
sup2 | U+00B2 |
sup3 | U+00B3 |
supe | U+2287 |
szlig | U+00DF |
tau | U+03C4 |
there4 | U+2234 |
theta | U+03B8 |
thetasym | U+03D1 |
thinsp | U+2009 |
thorn | U+00FE |
tilde | U+02DC |
times | U+00D7 |
trade | U+2122 |
uArr | U+21D1 |
uacute | U+00FA |
uarr | U+2191 |
ucirc | U+00FB |
ugrave | U+00F9 |
uml | U+00A8 |
upsih | U+03D2 |
upsilon | U+03C5 |
uuml | U+00FC |
weierp | U+2118 |
xi | U+03BE |
yacute | U+00FD |
yen | U+00A5 |
yuml | U+00FF |
zeta | U+03B6 |
zwj | U+200D |
zwnj | U+200C |
This section will probably include details on how to render DATAGRID, drag-and-drop, etc, in a visual medium, in concert with CSS. Terms that need to be defined include: sizing of embedded content
CSS UAs in visual media must, when scrolling a page to a fragment identifier, align the top of the viewport with the target element's top border edge.
This section is wrong. mediaMode will end up on Window, I think. All views implement Window.
Any object implement the AbstractView
interface must also implement the MediaModeAbstractView
interface.
interface MediaModeAbstractView { readonly attribute DOMString mediaMode;};
The mediaMode
attribute on objects implementing the MediaModeAbstractView
interface must return the string that represents the canvas' current rendering mode (screen
, print
, etc). This is a lowercase string, as defined by the CSS specification. [CSS21]
Some user agents may support multiple media, in which case there will exist multiple objects implementing the AbstractView
interface. Only the default view implements the Window
interface. The other views can be reached using the view
attribute of the UIEvent
inteface, during event propagation. There is no way currently to enumerate all the views.
This section is non-normative.
There are certain features that are not handled by this specification because a client side markup language is not the right level for them, or because the features exist in other languages that can be integrated into this one. This section covers some of the more common requests.
If you wish to create localised versions of an HTML application, the best solution is to preprocess the files on the server, and then use HTTP content negotation to serve the appropriate language.
Embedding vector graphics into XHTML documents is the domain of SVG.
Embedding 3D imagery into XHTML documents is the domain of X3D, or technologies based on X3D that are namespace-aware.
DocumentStyle
interfaceThis section describes an extension to the DocumentStyle
interface introduced in DOM2 Style. [DOM2STYLE]
It is expected that this section will be moved to a W3C CSS working group or WebAPI working group specification in the next few months.
// Introduced in DOM Level 2: [DOM2STYLE]interface DocumentStyle { readonly attribute StyleSheetList styleSheets; // New in this specification: attribute DOMString selectedStyleSheetSet; readonly attribute DOMString lastStyleSheetSet; readonly attribute DOMString preferredStyleSheetSet; readonly attribute DOMStringList styleSheetSets; void enableStyleSheetsForSet(in DOMString name);};
Any object implementing the HTMLDocument
interface must also implement the DocumentStyle
interface.
For this interface, the DOMString
values "null" and "the empty string" are distinct, and must not be considered equivalent.
A style sheet is said to have a title if the title
attribute or pseudo-attribute of the DOM node that introduced the style sheet is present and has a non-empty value (i.e. if the title
attribute of the StyleSheet
object returned by the sheet
attribute of the LinkStyle
interface of that DOM node is neither null nor the empty string).
The new members are defined as follows:
selectedStyleSheetSet
of type DOMString
This attribute indicates which style sheet set ([HTML4]) is in use. This attribute is live; changing the disabled attribute on style sheets directly will change the value of this attribute.
If all the sheets that are enabled and have a title have the same title (by case-sensitive comparisons) then the value of this attribute must be exactly equal to the title of the first enabled style sheet with a title in the styleSheets
list. Otherwise, if style sheets from different sets are enabled, then the return value must be null (there is no way to determine what the currently selected style sheet set is in those conditions). Otherwise, either all style sheets that have a title are disabled, or there are no alternate style sheets, and selectedStyleSheetSet
must return the empty string.
Setting this attribute to the null value must have no effect.
Setting this attribute to a non-null value must call enableStyleSheetsForSet()
with that value as the function's argument, and set lastStyleSheetSet
to that value.
From the DOM's perspective, all views have the same selectedStyleSheetSet
. If a UA supports multiple views with different selected alternate style sheets, then this attribute (and the StyleSheet
interface's disabled
attribute) must return and set the value for the default view.
lastStyleSheetSet
of type DOMString
, readonly This property must initially have the value null. Its value changes when the selectedStyleSheetSet
attribute is set.
preferredStyleSheetSet
of type DOMString
, readonly This attribute must return the preferred style sheet set as set by the author. It is determined from the order of style sheet declarations and the Default-Style
HTTP headers, as eventually defined elsewhere in this specification. If there is no preferred style sheet set, this attribute must return the empty string. The case of this attribute must exactly match the case given by the author where the preferred style sheet is specified or implied. This attribute must never return null.
styleSheetSets
of type DOMStringList
, readonly This must return the live list of the currently available style sheet sets. This list is constructed by enumerating all the style sheets for this document available to the implementation, in the order they are listed in the styleSheets
attribute, adding the title of each style sheet with a title to the list, avoiding duplicates by dropping titles that match (case-sensitively) titles that have already been added to the list.
enableStyleSheetsForSet(name)
, method Calling this method must change the disabled
attribute on each StyleSheet
object with a title attribute with a length greater than 0 in the styleSheets
attribute, so that all those whose title matches the name argument are enabled, and all others are disabled. Title matches must be case-sensitive. Calling this method with the empty string disables all alternate and preferred style sheets (but does not change the state of persistent style sheets, that is those with no title attribute).
Calling this method with a null value must have no effect.
Style sheets that do not have a title are never affected by this method. This method does not change the values of the lastStyleSheetSet
or preferredStyleSheetSet
attributes.
If new style sheets with titles are added to the document, the UA must decide whether or not the style sheets should be initially enabled or not. How this happens depends on the exact state of the document at the time the style sheet is added, as follows.
First, if the style sheet is a preferred style sheet (it has a title, but is not marked as alternate), and there is no current preferred style sheet (the preferredStyleSheetSet
attribute is equal to the empty string) then the preferredStyleSheetSet
attribute is set to the exact value of this style sheet's title. (This changes the preferred style sheet set, which causes further changes AMPERSANDmdash; see below.)
Then, for all sheets, if any of the following is true, then the style sheet must be enabled:
lastStyleSheetSet
is null, and the style sheet's title matches (by case-sensitive match) the value of the preferredStyleSheetSet
attribute. lastStyleSheetSet
attribute. Otherwise, the style sheet must be disabled.
The first time the preferred style sheet set is set, which is either before any alternate style sheets are seen (e.g. using a "Default-Style" HTTP header), or is the first time a titled, non-alternate style sheet is seen (in the absence of information to the contrary, the first titled non-alternate sheet sets the name of the preferred set), the preferredStyleSheetSet
attribute's value must be set to the name of that preferred style sheet set. This does not change the lastStyleSheetSet
attribute.
If the UA has the preferred style sheet set changed, for example if it receives a "Default-Style:" HTTP header after it receives HTTP "Link:" headers implying another preferred style sheet, then the preferredStyleSheetSet
attribute's value must be changed appropriately, and, if the lastStyleSheetSet
is null, the enableStyleSheetsForSet()
method must be called with the new preferredStyleSheetSet
value. (The lastStyleSheetSet
attribute is, again, not changed.)
Thus, in the following HTML snippet:
AMPERSANDlt;link rel="alternate stylesheet" title="foo" href="a"AMPERSANDgt;AMPERSANDlt;link rel="alternate stylesheet" title="bar" href="b"AMPERSANDgt;AMPERSANDlt;scriptAMPERSANDgt; document.selectedStyleSheetSet = 'foo'; document.styleSheets[1].disabled = false;AMPERSANDlt;/scriptAMPERSANDgt;AMPERSANDlt;link rel="alternate stylesheet" title="foo" href="c"AMPERSANDgt;AMPERSANDlt;link rel="alternate stylesheet" title="bar" href="d"AMPERSANDgt;
...the style sheets that end up enabled are style sheets "a", "b", and "c", the selectedStyleSheetSet
attribute would return null, lastStyleSheetSet
would return "foo", and preferredStyleSheetSet
would return "".
Similarly, in the following HTML snippet:
AMPERSANDlt;link rel="alternate stylesheet" title="foo" href="a"AMPERSANDgt;AMPERSANDlt;link rel="alternate stylesheet" title="bar" href="b"AMPERSANDgt;AMPERSANDlt;scriptAMPERSANDgt; var before = document.preferredStyleSheetSet; document.styleSheets[1].disabled = false;AMPERSANDlt;/scriptAMPERSANDgt;AMPERSANDlt;link rel="stylesheet" title="foo" href="c"AMPERSANDgt;AMPERSANDlt;link rel="alternate stylesheet" title="bar" href="d"AMPERSANDgt;AMPERSANDlt;scriptAMPERSANDgt; var after = document.preferredStyleSheetSet;AMPERSANDlt;/scriptAMPERSANDgt;
...the "before" variable will be equal to the empty string, the "after" variable will be equal to "foo", and style sheets "a" and "c" will be enabled. This is the case even though the first script block sets style sheet "b" to be enabled, because upon parsing the following AMPERSANDlt;linkAMPERSANDgt;
element, the preferredStyleSheetSet
is set and the enableStyleSheetsForSet()
method is called (since selectedStyleSheetSet
was never set explicitly, leaving lastStyleSheetSet
at null throughout), which changes which style sheets are enabled and which are not.
The user interface of Web browsers that support style sheets should list the style sheet titles given in the styleSheetSets
list, showing the selectedStyleSheetSet
as the selected style sheet set, leaving none selected if it is null or the empty string, and selecting an extra option "Basic Page Style" (or similar) if it is the empty string and the preferredStyleSheetSet
is the empty string as well.
Selecting a style sheet from this list should set the selectedStyleSheetSet
attribute. This (by definition) affects the lastStyleSheetSet
attribute.
If UAs persist the selected style sheet set, they should use the value of the selectedStyleSheetSet
attribute, or if that is null, the lastStyleSheetSet
attribute, when leaving the page (or at some other time) to determine the set name to store. If that is null then the style sheet set should not be persisted.
When re-setting the style sheet set to the persisted value (which can happen at any time, typically at the first time the style sheets are needed for styling the document, after the AMPERSANDlt;headAMPERSANDgt;
of the document has been parsed, after any scripts that are not dependent on computed style have executed), the style sheet set should be set by setting the selectedStyleSheetSet
attribute as if the user had selected the set manually.
This specification does not give any suggestions on how UAs should decide to persist the style sheet set or whether or how to persist the selected set across pages.
Future versions of CSS may introduce ways of having alternate style sheets declared at levels lower than the top level, i.e. embedded within other style sheets. Implementations of this specification that also support this proposed declaration of alternate style sheets are expected to perform depth-first traversals of the styleSheets
list, not simply enumerations of the styleSheets
list that only contains the top level.
This section is expected to be moved to the Window Object specification in due course.
interface WindowTimers { // timers long setTimeout(in TimeoutHandler handler, in long timeout); long setTimeout(in TimeoutHandler handler, in long timeout, arguments...); long setTimeout(in DOMString code, in long timeout); long setTimeout(in DOMString code, in long timeout, in DOMString language); void clearTimeout(in long handle); long setInterval(in TimeoutHandler handler, in long timeout); long setInterval(in TimeoutHandler handler, in long timeout, arguments...); long setInterval(in DOMString code, in long timeout); long setInterval(in DOMString code, in long timeout, in DOMString language); void clearInterval(in long handle);};interface TimeoutHandler { void handleEvent(arguments...);};
The WindowTimers
interface must be obtainable from any Window
object using binding-specific casting methods.
The setTimeout
and setInterval
methods allow authors to schedule timer-based events.
The setTimeout(handler, timeout[, arguments...])
method takes a reference to a TimeoutHandler
object and a length of time in milliseconds. It must return a handle to the timeout created, and then asynchronously wait timeout milliseconds and then invoke handleEvent()
on the handler object. If any arguments... were provided, they must be passed to the handler as arguments to the handleEvent()
function.
In the ECMAScript DOM binding, the ECMAScript native Function
type must implement the TimeoutHandler
interface such that invoking the handleEvent()
method of that interface on the object from another language binding invokes the function itself, with the arguments passed to handleEvent()
as the arguments passed to the function. In the ECMAScript DOM binding itself, however, the handleEvent()
method of the interface is not directly accessible on Function
objects. Such functions must be called in the global scope.
Alternatively, setTimeout(code, timeout[, language])
may be used. This variant takes a string instead of a TimeoutHandler
object. That string must be parsed using the specified language (defaulting to ECMAScript if the third argument is omitted) and executed in the global scope.
Need to define language values.
The setInterval(...)
variants must work in the same way as the setTimeout
variants except that the handler or code
must be invoked again every timeout milliseconds, not just the once.
The clearTimeout()
and clearInterval()
methods take one integer (the value returned by setTimeout
and setInterval
respectively) and must cancel the specified timeout. When called with a value that does not correspond to an active timeout or interval, the methods must return without doing anything.
Timeouts must never fire while another script is executing. (Thus the HTML scripting model is strictly single-threaded and not reentrant.)
This section will be written in a future draft.
Thanks to Aankhen, Aaron Leventhal, Alexey Feldgendler, Anne van Kesteren, Anthony Hickson, AsbjAMPERSANDoslash;rn Ulsberg, Ben Godfrey, Ben Meadowcroft, Benjamin Hawkes-Lewis, Bjoern Hoehrmann, Boris Zbarsky, Brad Fults, Brad Neuberg, Brendan Eich, Brett Wilson, Channy Yun, Charl van Niekerk, Christian Biesinger, Christian Johansen, Chriswa, Daniel Peng, Darin Fisher, Dave Townsend, David Baron, David Flanagan, David Hyatt, Derek Featherstone, Dimitri Glazkov, dolphinling, Doron Rosenberg, Eira Monstad, Elliotte Harold, Erik Arvidsson, fantasai, Franck 'Shift' QuAMPERSANDeacute;lain, HAMPERSANDaring;kon Wium Lie, Henri Sivonen, Henrik Lied, Ignacio Javier, J. King, James Graham, James M Snell, James Perrett, Jan-Klaas Kollhof, Jasper Bryant-Greene, Jens Bannmann, Joel Spolsky, Johnny Stenback, Jon Perlow, Jonathan Worent, Jukka K. Korpela, Kai Hendry, Kornel Lesinski, Lachlan Hunt, Larry Page, Laurens Holst, Lenny Domnitser, LAMPERSANDeacute;onard Bouchet, Leons Petrazickis, Logan, Maciej Stachowiak, Malcolm Rowe, Mark Nottingham, Mark Schenk, Martijn Wargers, Martin Honnen, Matthew Mastracci, Matthew Raymond, Matthew Thomas, Mattias Waldau, Max Romantschuk, Michael 'Ratt' Iannarelli, Michael A. Nachbaur, Michael Gratton, Michel Fortin, Mihai AMPERSAND#x015E;ucan, Mike Schinkel, Mike Shaver, Mikko Rantalainen, Neil Deakin, Olav Junker KjAMPERSANDaelig;r, Rimantas Liubertas, Robert O'Callahan, Robert Sayre, Roman Ivanov, S. Mike Dierken, Sam Ruby, Shadow2531, Shaun Inman, Simon Pieters, Stephen Ma, Steve Runyon, Steven Garrity, Stewart Brodie, Stuart Parmenter, Tantek AMPERSANDCcedil;elik, Thomas Broyer, Thomas O'Connor, Tim Altman, Vladimir VukiAMPERSAND#x0107;eviAMPERSAND#x0107;, William Swanson, and everyone on the WHATWG mailing list for their useful and substantial comments.
Special thanks to Richard Williamson for creating the first implementation of canvas
in Safari, from which the canvas feature was designed.
Special thanks also to the Microsoft employees who first implemented the event-based drag-and-drop mechanism, contenteditable
, and other features first widely deployed by the Windows Internet Explorer browser.
Special thanks and $10,000 to David Hyatt who came up with a broken implementation of the adoption agency algorithm that the editor had to reverse engineer and fix before using it in the parsing section.
Thanks also the Microsoft blogging community for some ideas, to the attendees of the W3C Workshop on Web Applications and Compound Documents for inspiration, and to the #mrt crew, the #mrt.no crew, and the cabal for their ideas and support.