DOM

Аннотация

DOM определяет платформенно-нейтральную модель для событий, прерывания действий и деревьев узлов.

Версия документа от 05 октября 2020 года.

Оглавление

Цели
1 Инфраструктура
  1.1 Деревья
  1.2 Заказанные наборы (Упорядоченное множество)
  1.3 Селекторы
  1.4 Пространства имен

2 События
  2.1 Введение в "События DOM"
  2.2 Интерфейс Event (Событие)
  2.3 Устаревшие расширения интерфейса Window
  2.4 Интерфейс CustomEvent (Пользовательское событие)
  2.5 Построение событий
  2.6 Определение интерфейсов событий
  2.7 Интерфейс EventTarget (Цель события)
  2.8 Наблюдение за слушателями событий
  2.9 Отправка событий
  2.10 Запуск событий
  2.11 Действие против события

3 Прерывание текущей деятельности
  3.1 Интерфейс AbortController (Прерывание контроллера)
  3.2 Интерфейс AbortSignal (Прерывание сигнала)
  3.3 Использование объектов AbortController и AbortSignal в API

4 Узлы
  4.1 Введение в "DOM"
  4.2 Дерево узлов
    4.2.1 Дерево документа
    4.2.2 Теневое дерево
      4.2.2.1 Слоты
      4.2.2.2 Таблицы слотов
      4.2.2.3 Поиск слотов и таблиц слотов
      4.2.2.4 Назначение таблиц слотов и слотов
      4.2.2.5 Сигнализация об изменении слота
    4.2.3 Алгоритмы мутации
    4.2.4 Смешивание NonElementParentNode (Неэлементный родительский узел)
    4.2.5 Смешивание DocumentOrShadowRoot (Документ или теневой корень)
    4.2.6 Смешивание ParentNode (Родительский узел)
    4.2.7 Смешивание NonDocumentTypeChildNode (Дочерний узел не типа документа)
    4.2.8 Смешивание ChildNode (Дочерний узел)
    4.2.9 Смешивание Slottable (Таблица слотов)
    4.2.10 Коллекции в старом стиле: NodeList и HTMLCollection
      4.2.10.1 Интерфейс NodeList (Список узлов)
      4.2.10.2 Интерфейс HTMLCollection (Коллекция HTML)
  4.3 Наблюдатели за мутациями
    4.3.1 Интерфейс MutationObserver (Наблюдатель за мутациями)
    4.3.2 Организация очереди записи мутации
    4.3.3 Интерфейс MutationRecord (Запись мутации)
    4.3.4 Сборка мусора
  4.4 Интерфейс Node (Узел)
  4.5 Интерфейс Document (Документ)
    4.5.1 Интерфейс DOMImplementation (Реализация DOM)
  4.6 Интерфейс DocumentType (Тип документа)
  4.7 Интерфейс DocumentFragment (Фрагмент документа)
  4.8 Интерфейс ShadowRoot (Теневой корень)
  4.9 Интерфейс Element (Элемент)
    4.9.1 Интерфейс NamedNodeMap (Карта именованных узлов)
    4.9.2 Интерфейс Attr (Атрибут)
  4.10 Интерфейс CharacterData (Символьные данные)
  4.11 Интерфейс Text (Текст)
  4.12 Интерфейс CDATASection (Раздел CDATA)
  4.13 Интерфейс ProcessingInstruction (Инструкция по обработке)
  4.14 Интерфейс Comment (Комментарий)

5 Диапазоны
  5.1 Введение в "Диапазоны DOM"
  5.2 Граничные точки
  5.3 Интерфейс AbstractRange (Абстрактный диапазон)
  5.4 Интерфейс StaticRange (Статический диапазон)
  5.5 Интерфейс Range (Диапазон)

6 Обход (Пересечение)
  6.1 Интерфейс NodeIterator (Итератор узла)
  6.2 Интерфейс TreeWalker (Обходчик дерева)
  6.3 Интерфейс NodeFilter (Фильтр узла)

7 Наборы
  7.1 Интерфейс DOMTokenList (Список токенов DOM)

8 XPath
  8.1 Интерфейс XPathResult (Результат XPath)
  8.2 Интерфейс XPathExpression (Выражение XPath)
  8.3 Смешивание XPathEvaluatorBase (База Оценщика XPath)
  8.4 Интерфейс XPathEvaluator (Оценщик XPath)

9 Исторические
  9.1 События DOM
  9.2 Ядро DOM
  9.3 Диапазоны DOM
  9.4 Обход DOM

Благодарности

Права интеллектуальной собственности

Индекс
  Термины, определенные в данной спецификации
  Термины определены ссылкой

Ссылки
  Нормативные ссылки
  Информативные ссылки

Индекс IDL

 

Цели

Эта спецификация стандартизирует DOM. Это происходит следующим образом:

1. Путем объединения «DOM Ядро Уровень 3»  [DOM-Level-3-Core], «Обход элементов» [ELEMENTTRAVERSAL], «API селекторов Уровень 2» [SELECTORS-API2], глав «Архитектура событий DOM» и «Базовые интерфейсы событий» из «DOM События Уровень 3» [uievents-20031107] (определенные типы событий не входят в стандарт DOM) и «DOM Обход и диапазон Уровень 2»  [DOM-Level-2-Traversal-Range], а также:

— По возможности согласовать их с экосистемой JavaScript.
— Согласование их с существующими реализациями.
— Максимально упрощая их.

2. Путем перемещения функций из стандарта HTML [HTML], которые имеют больше смысла указывать как часть стандарта DOM.

3. Путем определения замены для глав «События мутации» и «Типы событий имени мутации» документа DOM Level 3 Events [uievents-20031107], поскольку старая модель была проблематичной.

Примечание Ожидается, что старая модель со временем будет исключена из реализаций.

4. Путем определения новых функций, упрощающих общие операции DOM.

 

1 Инфраструктура

Эта спецификация зависит от стандарта Infra. [INFRA]

Некоторые термины, используемые в этой спецификации, определены в разделах «Кодирование», «Селекторы», «Web IDL», «XML» и «Пространства имен в XML». [ENCODING]  [SELECTORS4]  [WEBIDL]  [XML]  [XML-NAMES]

Термин «объект контекста» (context object) является для псевдонимом термина this.

Примечание Использование объекта контекста не рекомендуется в пользу this.

Когда требуются расширения, можно соответствующим образом обновить стандарт DOM или написать новый стандарт, который будет привязан к предоставленным крючкам расширяемости для соответствующих спецификаций (applicable specifications).

 

1.1 Деревья

«Дерево» (tree) — это конечная иерархическая древовидная структура. В «древовидном порядке» (tree order) — это предварительный обход дерева в глубину.

У объекта, который «участвует» (participates) в дереве, есть «родитель» (parent), который является либо null, либо объектом, и имеет «детей» (children), которые представляют собой упорядоченный набор объектов. Объект A, чьим родителем является объект B — является ребёнком B.

«Корнем» (root) объекта является он сам, если его родитель равен нулю, или же он является корнем своего родителя. Корнем дерева является любой объект, участвующий в этом дереве, родитель которого равен нулю.

Объект A называется «потомком» (descendant) объекта B, если либо A является ребёнком B, либо A является ребёнком объекта C, который является потомком B.

«Инклюзивный потомок» (inclusive descendant) — это объект или один из его потомков.

Объект A называется «предком» (ancestor) объекта B тогда и только тогда, когда B является потомком A.

«Инклюзивный предок» (inclusive ancestor) — это объект или один из его предков.

Объект A называется «родственником» (sibling) объекта B тогда и только тогда, когда B и A имеют одного и того же ненулевого родителя.

«Инклюзивный родственник» (inclusive sibling) — это объект или один из его родственников (братьев и сестер).

Объект A «предшествует» (preceding) объекту B, если A и B находятся в одном дереве, а A стоит перед B в порядке дерева.

Объект A «следует» (following) за объектом B, если A и B находятся в одном дереве, а A идет после B в порядке дерева.

«Первый ребёнок» (first child) объекта — это его первый ребёнок или null, если у него нет детей.

«Последний ребёнок» (last child) объекта — это его последний ребёнок или null, если у него нет детей.

«Предыдущий родственник» (previous sibling) объекта является его первым предшествующим родственником или null, если у него нет предшествующего родственника (брата или сестры).

«Следующим родственником» (next sibling) объекта является его первый следующий родственник или null, если у него нет следующего родственника.

«Индекс» (index) объекта — это количество предшествующих ему родственников (братьев и сестер), или 0, если у него их нет.

 

1.2 Упорядоченные наборы

«Синтаксический анализатор упорядоченного набора» (ordered set parser) принимает строковый ввод input и затем выполняет следующие шаги:

1. Пусть inputTokens будет результатом разделения ввода input на пробелы ASCII.
2. Пусть токены tokens будут новым упорядоченным набором.
3. Для каждого токена token в inputTokens добавьте token к tokens.
4. Верните tokens.

«Сериализатор упорядоченного набора» (ordered set serializer) принимает набор set и возвращает конкатенацию набора set, используя U+0020 SPACE.

 

1.3 Селекторы

Чтобы «сопоставить строку селекторов» (scope-match a selectors string) selectors с узлом node, выполните следующие действия:

1. Пусть s будет результатом синтаксического анализа селектора selectors. [SELECTORS4]
2. Если s является ошибкой, выбросить исключение DOMException "SyntaxError".
3. Возвращает результат сопоставления селектора с деревом с s и корнем узла node, используя область видимости корневого узла node. [SELECTORS4]

Примечание Поддержка пространств имен в селекторах не планируется и не будет добавлена.

1.4 Пространства имен

Чтобы «проверить» (validate) квалифицированное имя qualifiedName, бросьте исключение DOMException «InvalidCharacterError«, если квалифицированное имя qualifiedName не соответствует производству Name или QName.

Чтобы «проверить и извлечь» (validate and extract) пространство имен namespace и квалифицированное имя qualifiedName, выполните следующие действия:

1. Если пространство имен namespace является пустой строкой, установите для нее значение null.
2. Проверьте qualifiedName.
3. Пусть префикс prefix будет null.
4. Пусть localName будет qualifiedName.
5. Если квалифицированное имя qualifiedName содержит ":" (U+003E), тогда разделите строку на нем и установите префикс prefix для части до и localName для части после.
6. Если префикс prefix не null, а пространство имен namespace равно null, то выдает исключение DOMException "NamespaceError".
7. Если префиксом prefix является "xml", а пространство имен namespace не является пространством имен XML, то выдайте исключение DOMException "NamespaceError".
8. Если либо qualifiedName, либо prefix равно "xmlns", а пространство имен namespace не является пространством имен XMLNS, то выдайте исключение DOMException "NamespaceError".
9. Если пространство имен namespace является пространством имен XMLNS, а ни qualifiedName, ни prefix не являются «xmlns», то выдать исключение DOMException "NamespaceError".
10. Вернуть namespace, prefix, and localName.

 

2 События

2.1 Введение в «События DOM»

На протяжении всей веб-платформы события отправляются объектам, чтобы сигнализировать о возникновении, например о сетевой активности или взаимодействии с пользователем. Эти объекты реализуют интерфейс EventTarget и поэтому могут добавлять прослушиватели событий для наблюдения за событиями, вызывая addEventListener():

obj.addEventListener("load", imgFetched)

function imgFetched(ev) {
// большой успех
…
}

Слушатели событий могут быть удалены с помощью метода removeEventListener(), передавшего те же аргументы.

События также являются объектами и реализуют интерфейс Event (или производный интерфейс). В приведенном выше примере ev — это событие. ev передается в качестве аргумента функции обратного вызова слушателя событий (обычно это функция JavaScript, как показано выше). Слушатели событий отключают значение атрибута type события («load» в приведенном выше примере). Значение атрибута target события возвращает объект, которому было отправлено событие (obj выше).

Хотя события обычно отправляются пользовательским агентом в результате взаимодействия с пользователем или завершения некоторой задачи, приложения могут сами отправлять события, используя так называемые синтетические события:

// добавление соответствующего слушателя событий
obj.addEventListener("cat", function(e) { process(e.detail) })

// создание и отправка события
var event = new CustomEvent("cat", {"detail":{"hazcheeseburger":true}})
obj.dispatchEvent(event)

Помимо сигнализации, иногда также используются события, позволяющие приложению контролировать дальнейшие действия в ходе операции. Например, как часть отправки формы отправляется событие, значение атрибута type которого равно «submit». Если вызывается метод preventDefault() этого события, отправка формы прекращается. Приложения, которые хотят использовать эту функциональность через события, отправленные приложением (синтетические события), могут использовать возвращаемое значение метода dispatchEvent():

if(obj.dispatchEvent(event)) {
// событие небыло отменено, время для магии
…
}

Когда событие отправляется объекту, который участвует в дереве (например, элементу), оно также может достигать слушателей событий на предках этого объекта. Фактически, все слушатели событий инклюзивных предков объекта, захват которых истинен, вызываются в древовидном порядке. А затем, если пузырьки bubbles события истинны, вызываются все слушатели событий инклюзивных предков объекта, захват которых ложен, теперь в обратном древовидном порядке.

Давайте посмотрим на пример того, как события работают в дереве:

<!doctype html>
<html>
   <head>
      <title>Boring example</title>
   </head>
   <body>
      <p>Hello <span id=x>world</span>!</p>
      <script>
         function test(e) {
            debug(e.target, e.currentTarget, e.eventPhase)
         }
         document.addEventListener("hey", test, {capture: true})
         document.body.addEventListener("hey", test)
         var ev = new Event("hey", {bubbles: true})
         document.getElementById("x").dispatchEvent(ev)
      </script>
   </body>
</html>

Функция отладки debug будет вызвана дважды. Каждый раз значение атрибута target события будет элементом span. В первый раз значением атрибута currentTarget будет документ, во второй раз — элемент body. Значение атрибута eventPhase переключается с CAPTURING_PHASE на BUBBLING_PHASE. Если бы слушатель событий был зарегистрирован для элемента span, значением атрибута eventPhase было бы AT_TARGET.

 

2.2 Интерфейс Event (Событие)

IDL

[Exposed=( Window , Worker , AudioWorklet )]
interface Event {
   constructor(DOMString type, optional EventInit eventInitDict = {});

   readonly attribute DOMString type;
   readonly attribute EventTarget? target;
   readonly attribute EventTarget? srcElement; // исторический
   readonly attribute EventTarget? currentTarget;
   sequence<EventTarget> composedPath();

   const unsigned short NONE = 0;
   const unsigned short CAPTURING_PHASE = 1;
   const unsigned short AT_TARGET = 2;
   const unsigned short BUBBLING_PHASE = 3;
   readonly attribute unsigned short eventPhase;

   undefined stopPropagation();
   attribute boolean cancelBubble; // исторический псевдоним .stopPropagation
   undefined stopImmediatePropagation();

   readonly attribute boolean bubbles;
   readonly attribute boolean cancelable;
            attribute boolean returnValue; // исторический
   undefined preventDefault();
   readonly attribute boolean defaultPrevented;
   readonly attribute boolean composed;

   [LegacyUnforgeable] readonly attribute boolean isTrusted;
   readonly attribute DOMHighResTimeStamp timeStamp;

   undefined initEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false); // исторический
};

dictionary EventInit {
   boolean bubbles = false;
   boolean cancelable = false;
   boolean composed = false;
};

 

Объект Event просто называется «событием» (event). Это позволяет сигнализировать о том, что что-то произошло, например, что изображение завершило загрузку.

«Потенциальная цель события» (potential event target) — null или объект EventTarget.

У события есть связанная «цель» (target) (потенциальная цель события). Если не указано иное, она не имеет значения (null).

У события есть связанная «родственная цель» (relatedTarget) (потенциальная цель события). Если не указано иное, она не имеет значения (null).

Примечание Другие спецификации используют relatedTarget для определения атрибута relatedTarget. [UIEVENTS]

У события есть связанный «список сенсорных целей» (touch target list) (список из нуля или более потенциальных целей события). Если не указано иное, это пустой список.

Примечание Список сенсорных целей предназначен исключительно для определения интерфейса TouchEvent и связанных интерфейсов. [TOUCH-EVENTS]

У события есть связанный «путь» (path). Путь — это список структур. Каждая структура состоит из «цели вызова» (invocation target) (объект EventTarget), из «цели вызова в теневом дереве» (invocation-target-in-shadow-tree) (логическое значение), из «цели с поправкой на тень» (shadow-adjusted target) (потенциальная цель события), из  «родственной цели» (relatedTarget) (потенциальная цель события), из «списка сенсорных целей» (touch target list) (список потенциальных целей событий), из «корня закрытого дерева» (root-of-closed-tree) (логическое значение) и из «слота в закрытом дереве» (slot-in-closed-tree) (логическое значение). Путь — это изначально пустой список.

 

Для веб-разработчиков (не нормативно)

event = new Event(type [, eventInitDict])

Возвращает новое событие event, для которого задано значение атрибута type как type. Аргумент eventInitDict позволяет устанавливать атрибуты bubbles и cancelable через элементы объекта с тем же именем.

event . type

Возвращает тип события event, например. «click», «hashchange» или «submit» (щелкнуть, изменить хэш или отправить)

event . target

Возвращает объект, которому отправлено событие event (его цель).

event . currentTarget

Возвращает объект, чей обратный вызов слушателя событий вызывается в данный момент.

event . composedPath()

Возвращает объекты цели вызова пути события event (объекты, для которых будут вызываться слушатели), за исключением любых узлов в теневых деревьях, для которых режим теневого корня «closed» (закрыт), которые недоступны из currentTarget события event.

event . eventPhase

Возвращает фазу события, которая может быть одной из NONE, CAPTURING_PHASE, AT_TARGET и BUBBLING_PHASE.

event . stopPropagation()

При отправке в дереве, вызов этого метода предотвращает достижение событием event каких-либо объектов, кроме текущего объекта.

event . stopImmediatePropagation()

Вызов этого метода предотвращает попадание события event в какие-либо зарегистрированные слушатели событий после завершения выполнения текущего, а при отправке в дереве также предотвращает достижение событием event любых других объектов.

event . bubbles

Возвращает истину или ложь в зависимости от того, как было инициализировано событие event. Истина, если событие event проходит через предков своей цели в обратном древовидном порядке, и ложь в противном случае.

event . cancelable

Возвращает истину или ложь в зависимости от того, как было инициализировано событие event. Его возвращаемое значение не всегда имеет смысл, но true может указывать на то, что часть операции, во время которой было отправлено событие event, может быть отменена путем вызова метода preventDefault().

event . preventDefault()

Если вызывается, когда значение атрибута cancelable равно true, и при выполнении слушателя для события event с passive значением false, сигнализирует операции, которая вызвала отправку события, что его необходимо отменить.

event . defaultPrevented

Возвращает true, если preventDefault() был успешно вызван для обозначения отмены, и false в противном случае.

event . composed

Возвращает истину или ложь в зависимости от того, как было инициализировано событие event. Истина, если событие event вызывает слушателей за узлом ShadowRoot, который является корнем его цели, и ложь в противном случае.

event . isTrusted

Возвращает true, если событие event было отправлено пользовательским агентом, и false в противном случае.

event . timeStamp

Возвращает отметку времени события event как количество миллисекунд, измеренных относительно начала отсчета времени.

 

 

Атрибут type должен возвращать значение, которым он был инициализирован. При создании события атрибут должен быть инициализирован пустой строкой.

Атрибут получателя target при вызове, должен возвращать цель этого (this).

Атрибут получателя srcElement при вызове, должен возвращать цель этого (this).

Атрибут currentTarget должен возвращать значение, которым он был инициализирован. При создании события атрибут должен быть инициализирован нулевым значением (null).

При вызове метода composedPath() необходимо выполнить следующие шаги:

1. Пусть composedPath будет пустым списком.
2. Пусть path будет путём этого this.
3. Если path пустой, тогда верните composedPath.
4. Пусть currentTarget будет значением атрибута currentTarget этого this.
5. Добавить currentTarget в composedPath.
6. Пусть currentTargetIndex будет "0".
7. Пусть currentTargetHiddenSubtreeLevel будет "0".
8. Пусть index будет размером − 1 пути path.
9. Пока index больше или равен 0:
   1. Если path[index] корня закрытого дерева истинен, то увеличьте currentTargetHiddenSubtreeLevel на 1.
   2. Если path[index] цели вызова является currentTarget, тогда установите currentTargetIndex на index и break.
   3. Если path[index] слота в закрытом дереве истинен, то уменьшите currentTargetHiddenSubtreeLevel на 1.
   4. Уменьшить index на 1.
10. Пусть currentHiddenLevel и maxHiddenLevel будут currentTargetHiddenSubtreeLevel.
11. Установите index на currentTargetIndex − 1.
12. Пока index больше или равен 0:
   1. Если path[index] корня закрытого дерева истинен, то увеличьте currentHiddenLevel на 1.
   2. Если currentHiddenLevel меньше или равен maxHiddenLevel, тогда добавляйте path[index] цели вызова в начало composedPath.
   3. Если path[index] слота в закрытом дереве истинен, то:
      1. Уменьшите currentHiddenLevel на 1.
      2. Если currentHiddenLevel меньше maxHiddenLevel, установите для maxHiddenLevel значение currentHiddenLevel.
   4. Уменьшить index на 1.
13. Установить currentHiddenLevel и maxHiddenLevel на currentTargetHiddenSubtreeLevel.
14. Установить index на currentTargetIndex + 1.
15. Пока index меньше размера пути path:
   1. Если path[index] слота в закрытом дереве истинен, увеличьте currentHiddenLevel на 1.
   2. Если currentHiddenLevel меньше или равен maxHiddenLevel, тогда добавьте path[index] цели вызова к composedPath.
   3. Если path[index] корня закрытого дерева истинен, то:
      1. Уменьшите currentHiddenLevel на 1.
      2. Если currentHiddenLevel меньше maxHiddenLevel, тогда установите maxHiddenLevel на currentHiddenLevel.
   4. Увеличить index на 1.
16. Вернуть composedPath.

 

Атрибут eventPhase должен возвращать значение, которым он был инициализирован, которое должно быть одним из следующих:

NONE (числовое значение 0)

На этом этапе находятся события, которые в настоящее время не отправляются.

CAPTURING_PHASE (числовое значение 1)

Когда событие отправляется объекту, который участвует в дереве, он будет в этой фазе, прежде чем достигнет своей цели.

AT_TARGET (числовое значение 2)

Когда событие отправлено, оно будет в этой фазе на своей цели.

BUBBLING_PHASE (числовое значение 3)

Когда событие отправляется объекту, который участвует в дереве, он будет в этой фазе после достижения своей цели.

Первоначально атрибут должен быть инициализирован как NONE.

 

Каждое событие имеет следующие связанные флаги, которые изначально не установлены:

Название флага Описание
stop propagation flag флаг остановки распространения
stop immediate propagation flag флаг немедленной остановки распространения
canceled flag флаг отмены
in passive listener flag флаг «в пассивном слушателе»
composed flag флаг составной
initialized flag флаг инициализации
dispatch flag флаг отправки

Метод stopPropagation() при вызове должен установить флаг остановки распространения этого this.

Получатель атрибута cancelBubble при вызове должен возвращать значение true, если установлен флаг остановки распространения этого this, и false в противном случае.

Установщик атрибута cancelBubble при вызове должен установить флаг остановки распространения этого this, если заданное значение истинно, и ничего не делать в противном случае.

При вызове метода stopImmediatePropagation() он должен установить флаг остановки распространения этого this и флаг остановки немедленного распространения этого this.

Атрибуты bubbles и cancelable должны возвращать значения, которыми они были инициализированы.

Чтобы «установить флаг отмены» (set the canceled flag) для данного события event, если значение атрибута cancelable события event истинно и флаг пассивного слушателя события event не установлен, установите флаг отмены события event и ничего не делайте в противном случае.

Получатель атрибута returnValue при вызове должен возвращать false, если установлен флаг отмены этого this, и true в противном случае.

Установщик атрибута returnValue при вызове должен установить флаг отмены с this, если заданное значение ложно, и ничего не делать в противном случае.

Метод preventDefault() при вызове должен установить флаг отмены с этим this.

Примечание Существуют сценарии, в которых вызов preventDefault() не имеет никакого эффекта. Пользовательским агентам рекомендуется регистрировать точную причину в консоли разработчика, чтобы облегчить отладку.

Получатель атрибута defaultPrevented при вызове должен возвращать true, если установлен флаг отмены этого this, и false в противном случае.

Получатель атрибута composed при вызове должен возвращать true, если установлен составной флаг этого this, и false в противном случае.

 

Атрибут isTrusted должен возвращать значение, которым он был инициализирован. При создании события атрибут должен иметь значение false.

Примечание isTrusted — это удобство, которое указывает, отправлено ли событие пользовательским агентом (в отличие от использования dispatchEvent()). Единственное устаревшее исключение — это click(), который заставляет пользовательский агент отправлять событие, атрибут isTrusted которого инициализируется значением false.

Атрибут timeStamp должен возвращать значение, которым он был инициализирован.

 

Чтобы «инициализировать» (initialize) событие event с типом type, пузырьками bubbles и возможностью отмены cancelable, выполните следующие действия:

1. Установить флаг инициализации для события event.
2. Снять флаг остановки распространения, флаг немедленной остановки распространения и флаг отмены для события event.
3. Установите для атрибута isTrusted события event значение false.
4. Установите для цели события event значение null.
5. Установите для атрибута type события event значение type.
6. Установите атрибут bubbles события event на bubbles.
7. Установите для атрибута cancelable события event значение cancelable.

 

При вызове метода initEvent (type, bubble, cancelable) необходимо выполнить следующие шаги:

1. Если установлен флаг отправки этого this, вернитесь.
2. Инициализируйте этот объект this с type, bubbles, и cancelable.

Примечание! Поскольку у событий есть конструкторы, initEvent() избыточен и не может быть настроен composed. Он должен поддерживаться для устаревшего контента.

 

2.3 Устаревшие расширения интерфейса Window

IDL

partial interface Window {
   [Replaceable] readonly attribute any event; // исторический
};

Каждый объект Window имеет связанное текущее событие (неопределенное — undefined или объект Event). Если не указано иное, он не определен.

Получатель атрибута события event при вызове должен возвращать текущее событие этого this.

Примечание! Веб-разработчикам настоятельно рекомендуется вместо этого полагаться на объект Event, передаваемый слушателям событий, так как это приведет к более переносимому коду. Этот атрибут недоступен в worker’ах или worklet’ах и неточен для событий, отправленных в теневых деревьях.

 

2.4 Интерфейс CustomEvent (Пользовательское событие)

IDL

[Exposed=( Window , Worker )]
interface CustomEvent : Event {
   constructor(DOMString type, optional CustomEventInit eventInitDict = {});

   readonly attribute any detail;

   undefined initCustomEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional any detail = null); // historical
};

dictionary CustomEventInit : EventInit {
   any detail = null;
};

 

События, использующие интерфейс CustomEvent, могут использоваться для переноса пользовательских данных.

Для веб-разработчиков (не нормативно)

event = new CustomEvent(type [, eventInitDict])

Работает аналогично конструктору для Event, за исключением того, что аргумент eventInitDict теперь позволяет также установить атрибут detail.

event . detail

Возвращает любое событие event пользовательских данных, созданное с помощью. Обычно используется для синтетических соревнований.

 

Атрибут detail должен возвращать значение, которым он был инициализирован.

При вызове метода initCustomEvent( type, bubbles, cancelable, detail ) должны выполняться следующие шаги:

1. Если установлен флаг отправки этого this, вернитесь.
2. Инициализировать этот this с type, bubbles и cancelable.
3. Установите для атрибута detail этого this значение detail.

 

2.5 Построение событий

Спецификации могут определять «шаги построения событий» (event constructing steps) для всех или некоторых событий. В алгоритм передается событие event, как указано на этапах создания внутреннего события.

Примечание Эта конструкция может использоваться подклассами Event, которые имеют более сложную структуру, чем простое отображение 1:1 между их инициализирующими элементами словаря и атрибутами IDL.

Когда вызывается «конструктор» (constructor) интерфейса Event или интерфейса, который наследуется от интерфейса Event, эти шаги должны быть выполнены с учетом типа аргументов и eventInitDict:

1. Пусть событие event будет результатом выполнения шагов создания внутреннего события с этим интерфейсом, null, now и eventInitDict.
2. Инициализировать атрибут type события event для type.
3. Вернуть event.

 

Чтобы «создать событие» (create event) с использованием eventInterface, которое должно быть либо событием Event, либо интерфейсом, наследуемым от него, и, возможно, с заданной областью Realm realm, выполните следующие действия:

1. Если область realm не указана, установите для нее значение null.
2. Пусть словарь будет результатом преобразования неопределенного значения JavaScript в тип словаря, принятый конструктором eventInterface. (Этот тип словаря будет либо EventInit, либо унаследованным от него словарем.)
   Это не работает, если требуются члены; см. whatwg/dom#600.
3. Пусть событие event будет результатом выполнения шагов создания внутреннего события с помощью eventInterface, realm, времени возникновения, о котором событие сигнализирует, и словаря dictionary.
   Пример! В macOS время возникновения действий ввода доступно через свойство timestamp объектов NSEvent.
4. Для атрибута isTrusted события event инициализируйте значение true.
5. Верните событие event

Примечание Создание события предназначено для использования другими спецификациями, которым необходимо отдельно создавать и отправлять события, а не просто запускать их. Это гарантирует, что атрибуты события инициализированы до правильных значений по умолчанию.

 

Шаги «создания внутреннего события» (inner event creation steps) с учетом интерфейса interface, области realm, времени time и словаря dictionary следующие:

1. Пусть событие event будет результатом создания нового объекта с помощью eventInterface. Если область не равна нулю (не null), используйте эту область; в противном случае используйте поведение по умолчанию, определенное в Web IDL.

   На момент написания этой статьи Web IDL еще не определял поведение по умолчанию; см. heycam/webidl#135.

2. Установить флаг инициализации события event.
3. Инициализируйте атрибут timeStamp события event как DOMHighResTimeStamp, представляющий время с высоким разрешением от начала отсчета времени до time.

   ВНИМАНИЕ! Пользовательские агенты должны установить минимальное разрешение атрибута timeStamp события на 5 микросекунд, следуя существующей рекомендации по разрешению часов. [HR-TIME]

4. Для каждой пары "member/value" в словаре dictionary, если событие event имеет атрибут, идентификатор которого является member, инициализируйте этот атрибут значением value.
5. Запустите шаги построения события с помощью event.
6. Верните событие event.

 

2.6 Определение интерфейсов событий

В общем, при определении нового интерфейса, наследуемого от Event, всегда запрашивайте отзывы у WHATWG или сообщества W3C WebApps WG.

Интерфейс CustomEvent можно использовать как отправную точку. Однако не вводите никаких методов init*Event(), поскольку они избыточны с конструкторами. Интерфейсы, наследующие от интерфейса Event и имеющие такой метод, имеют его только по историческим причинам.

 

2.7 Интерфейс EventTarget (Цель события)

IDL

[Exposed=( Window , Worker , AudioWorklet )]
interface EventTarget {
   constructor();

   undefined addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options = {});
   undefined removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options = {});
   boolean dispatchEvent(Event event);
};

callback interface EventListener {
   undefined handleEvent(Event event);
};

dictionary EventListenerOptions {
   boolean capture = false;
};

dictionary AddEventListenerOptions : EventListenerOptions {
   boolean passive = false;
   boolean once = false;
};

 

Объект EventTarget представляет цель, которой может быть отправлено событие, когда что-то произошло.

Каждый объект EventTarget имеет связанный «список слушателей событий» (event listener list) (список из нуля или более слушателей событий). Изначально это пустой список.

«Слушатель событий» (event listener) может использоваться для наблюдения за конкретным событием и состоит из:

1. type (строка)
2. callback (null или объект EventListener)
3. capture (a boolean, изначально ложный false)
4. passive (a boolean, изначально ложный false)
5. once (a boolean, изначально ложный false)
6. removed (a boolean для бухгалтерских целей, изначально ложный false)

Примечание! Хотя обратный вызов является объектом EventListener, слушатель событий — это более широкая концепция, как видно выше.

 

С каждым объектом EventTarget также связан алгоритм «получения родителя» (get the parent), который принимает событие event и возвращает объект EventTarget. Если не указано иное, возвращается значение null.

Примечание Узлы, теневые корни и документы переопределяют алгоритм получения родителя.

 

Каждый объект EventTarget может иметь связанный алгоритм «поведения активации» (activation behavior). Алгоритм поведения активации передает событие, как указано в алгоритме отправки.

Примечание Это происходит потому, что пользовательские агенты выполняют определенные действия для определенных объектов EventTarget, например, элемента области area, в ответ на синтетические события MouseEvent, атрибут type которых — click. Веб-совместимость помешала его удалению, и теперь это закрепленный способ определения активации чего-либо. [HTML]

 

Каждый объект EventTarget, который имеет поведение активации, может дополнительно иметь как алгоритм «устаревшей предварительной активации поведения» (legacy-pre-activation behavior), так и алгоритм «устаревшей отмены активации поведения» (legacy-canceled-activation behavior).

Примечание Эти алгоритмы существуют только для флажков и радиоэлементов ввода input и не должны использоваться ни для чего другого. [HTML]

 

Для веб-разработчиков (не нормативно)

target = new EventTarget()

Создает новый объект EventTarget, который может использоваться разработчиками для отправки и прослушивания событий.

target . addEventListener(type, callback [, options])

Добавляет слушатель событий для событий, значение атрибута type которых — type. Аргумент callback устанавливает обратный вызов, который будет вызываться при отправке события.

Аргумент options устанавливает параметры для конкретного слушателя. Для совместимости это может быть логическое значение, и в этом случае метод ведет себя точно так же, как если бы значение было указано в качестве захвата параметров — capture options.

Если задано значение true, захват параметров capture options предотвращает вызов обратного вызова, когда значение атрибута eventPhase события равно BUBBLING_PHASE. Если указано значение false (или отсутствует), обратный вызов не будет вызываться, если значение атрибута eventPhase для события равно CAPTURING_PHASE. В любом случае обратный вызов будет вызываться, если значение атрибута eventPhase для события равно AT_TARGET.

Если установлено значение true, параметр passive options указывает, что обратный вызов не отменит событие путем вызова preventDefault(). Это используется для включения оптимизации производительности, описанной в §2.8 Наблюдение за слушателями событий.

Если установлено значение true, параметр once options указывает, что обратный вызов будет вызываться только один раз, после чего слушатель событий будет удален.

Слушатель событий добавляется к списку слушателей событий цели target и не добавляется, если он имеет тот же тип, обратный вызов и захват.

target . removeEventListener(type, callback [, options])

Удаляет слушатель событий из целевого списка слушателей событий с тем же типом type, обратным вызовом callback и параметрами options.

target . dispatchEvent(event)

Отправляет синтетическое событие event в цель target и возвращает true, если значение атрибута cancelable события event  равно false или его метод preventDefault() не был вызван, и false в противном случае.

 

Чтобы «сгладить» (flatten) параметры options, выполните следующие действия:

1. Если options является логическим, верните options.
2. Вернуть capture options.

 

Чтобы «сгладить больше» (flatten more) параметров options, выполните следующие действия:

1. Пусть захват capture будет результатом параметров options сглаживания.
2. Пусть once и passive будет ложным.
3. Если options - это словарь, то установите passive на passive от options, а once на once от options.
4. Верните capture, passive и once.

 

Конструктор EventTarget() при вызове должен возвращать новый EventTarget.

Примечание Из-за значений по умолчанию, указанных в другом месте, возвращенный EventTarget алгоритм получения родителя вернет null, и у него не будет поведения активации, устаревшего поведения предварительной активации или устаревшего поведения отмененной активации.

Примечание В будущем мы могли бы разрешить настраиваемость алгоритма получение родителя. Сообщите нам, будет ли это полезно для ваших программ. На данный момент все созданные автором EventTarget не участвуют в древовидной структуре.

 

Чтобы «добавить слушатель событий» (add an event listener), учитывая объект EventTarget eventTarget и слушатель событий listener, выполните следующие действия:

1. Если eventTarget является объектом ServiceWorkerGlobalScope, установлен флаг какой-либо оценки ресурса сценария его сервис-воркера, а тип слушателя listener совпадает со значением атрибута type любого из событий сервисного работника, а затем отправляет предупреждение в консоль, что это может не дать ожидаемого получения результата. [SERVICE-WORKERS]
2. Если обратный вызов слушателя listener равен нулю, вернитесь.
3. Если список слушателей событий eventTarget не содержит слушателя событий, тип которого является типом listener, обратный вызов - это обратный вызов listener, а захват - это захват listener, тогда добавьте listener в список слушателей событий eventTarget.

Примечание Концепция добавления слушателя событий существует, чтобы гарантировать, что обработчики событий используют один и тот же путь кода. [HTML]

 

При вызове метода addEventListener (type, callback, options) необходимо выполнить следующие шаги:

1. Пусть capture, passive и once будет результатом сглаживания большего количества вариантов options.
2. Добавьте слушатель событий с этим this и слушатель событий, тип которого - type, обратный вызов - callback, захват - capture, пассивный - passive, и "один раз" - once.

 

Чтобы «удалить слушатель событий» (remove an event listener), учитывая объект EventTarget, eventTarget и слушатель событий, выполните следующие действия:

1. Если eventTarget является объектом ServiceWorkerGlobalScope и набор типов событий для обработки его сервис-воркера содержит type, то отправьте на консоль предупреждение о том, что это может не дать ожидаемых результатов. [SERVICE-WORKERS]
2. Установите для удалённого listener значение true и удалите его из списка слушателей событий eventTarget.

Примечание Это необходимо HTML для определения обработчиков событий. [HTML]

 

Чтобы «удалить все слушатели событий» (remove all event listeners), учитывая объект EventTarget eventTarget, для каждого слушателя listener из списка слушателей событий eventTarget, удалите слушатель событий с eventTarget и listener.

Примечание Это необходимо HTML для определения document.open(). [HTML]

 

При вызове метода removeEventListener(type, callback, options) необходимо выполнить следующие действия:

1. Пусть захват capture будет результатом сглаживания параметров options.
2. Если список слушателей событий этого this содержит слушатель событий, тип которого - type, обратный вызов - callback, а захват - capture, то удалите слушатель событий с этим this и этим слушателем событий.

Примечание Список слушателей событий не будет содержать нескольких слушателей событий с одинаковым типом, обратным вызовом и захватом, поскольку добавление слушателя событий предотвращает это.

 

При вызове метода dispatchEvent(event) необходимо выполнить следующие действия:

1. Если установлен флаг отправки события event или если его флаг инициализации не установлен, то генерируется исключение DOMException "InvalidStateError".
2. Установите для атрибута isTrusted события event значение false.
3. Вернуть в результат отправки события event этого this.

 

2.8 Наблюдение за слушателями событий

В целом разработчики не ожидают, что присутствие слушателя событий будет заметным. Воздействие слушателя событий определяется его обратным вызовом. То есть разработчик, добавляющий слушатель событий без операции, не ожидает от него каких-либо побочных эффектов.

К сожалению, некоторые API-интерфейсы событий были разработаны таким образом, что их эффективная реализация требует наблюдения за слушателями событий. Это может сделать присутствие слушателей наблюдаемым в том смысле, что даже пустые слушатели могут оказать существенное влияние на производительность на поведение приложения. Например, события касания и колеса, которые можно использовать для блокировки асинхронной прокрутки. В некоторых случаях эту проблему можно смягчить, указав отменяемое событие cancelable только при наличии хотя бы одного не-пассивного слушателя (non-passive). Например, non-passive слушатели TouchEvent должны блокировать прокрутку, но если все слушатели пассивны (passive), прокрутку можно разрешить запускать параллельно, сделав TouchEvent неотменяемым (так, чтобы вызовы preventDefault() игнорировались). Таким образом, код, отправляющий событие, может отслеживать отсутствие non-passive слушателей и использовать это для очистки свойства cancelable для отправляемого события.

В идеале любые новые API-интерфейсы событий должны быть определены таким образом, что им не нужно это свойство (для обсуждения используйте public-script-coord@w3.org).

 

2.9 Отправка событий

Чтобы «отправить» (dispatch) событие event в цель target с необязательным флагом переопределения устаревшей цели (legacy target override flag) и необязательным legacyOutputDidListenersThrowFlag, выполните следующие действия:

1. Установить флаг отправки события event.
2. Пусть targetOverride будет target, если legacy target override flag не задан, а в противном случае - связанным с ним Document target. [HTML]
   Примечание Флаг переопределения устаревшей цели используется только HTML и только тогда, когда целью является объект Window.
3. Пусть activationTarget будет null.
4. Пусть relatedTarget будет результатом переопределения цели события event relatedTarget против target.
5. Если target не является relatedTarget или target это relatedTarget события event , тогда:
   1. Пусть touchTargets будет новым списком.
   2. Для каждого touchTarget в списке объектов касания цели события event, добавьте результат перенацеливания touchTarget на target в touchTargets.
   3. Добавьте к пути события с помощью event, target, targetOverride, relatedTarget, touchTargets и false.
   4. Пусть isActivationEvent имеет значение true, если событие является объектом MouseEvent, а атрибут type события event - "click", и false в противном случае.
   5. Если isActivationEvent имеет значение true и цель target имеет поведение активации, установите для параметра activateTarget значение target.
   6. Пусть таблица слотов slottable будет целью target, если цель является таблицей слот и назначена, и null в противном случае.
   7. Пусть slot-in-closed-tree будет false.
   8. Пусть parent будет результатом вызова получения родителя target с событием event.
   9. До тех пор пока parent не является null:
      1. Если slottable не null:
         1. Утверждение: родитель parent - это слот.
         2. Установить slottable на null.
         3. Если корень parent является теневым корнем, режим которого "closed", то установите для slot-in-closed-tree значение true.
      2. Если parent является таблицей слотов и назначен, установите для slottable значение parent.
      3. Пусть relatedTarget будет результатом события перенацеливания relatedTarget события event для родителя parent.
      4. Пусть touchTargets будет новым списком.
      5. Для каждого touchTarget в списке целевых объектов касания, добавьте результат перенацеливания touchTarget на родителя parent в touchTargets.
      6. Если родитель parent является объектом Window, или parent является узлом, а корень целевого объекта target является включающим тень предком родителя parent, тогда:
         1. Если isActivationEvent имеет значение true, атрибут bubbles события event имеет значение true, activationTarget имеет значение null, а parent имеет поведение активации, затем установите для activationTarget значение parent.
         2. Добавьте к пути события с помощью event, parent, null, relatedTarget, touchTargets и slot-in-closed-tree (слот-в-закрытом дереве).
      7. В противном случае, если parent - это relatedTarget, установите для parent значение null.
      8. В противном случае установите target как parent, а затем:
         1. Если isActivationEvent имеет значение true, activationTarget имеет значение null, а цель target имеет поведение активации, тогда установите activationTarget в значение target.
         2. Добавьте к пути события с помощью event, parent, target, relatedTarget, touchTargets и slot-in-closed-tree.
      9. Если parent не null, тогда установите parent равным результату вызова parent, чтобы получить родителя parent с событием event.
      10. Установить slot-in-closed-tree в значение false.
   10. Пусть clearTargetsStruct будет последней структурой в пути события event, чья цель с корректировкой тени не равна null.
   11. Пусть clearTargets имеет значение true, если цель с корректировкой тени clearTargetsStruct, relatedTarget clearTargetsStruct или объект EventTarget в списке сенсорных целей clearTargetsStruct является узлом, а его корень является теневым корнем, и false в противном случае.
   12. Если activationTarget не имеет значения NULL и activationTarget имеет устаревшее поведение предварительной активации, запустите устаревшее поведение предварительной активации activationTarget.
   13. Для каждой структуры struct в пути события event в обратном порядке:
      1. Если цель с корректировкой тени структуры struct не равна null, тогда установите для атрибута eventPhase события event значение AT_TARGET.
      2. В противном случае установите для атрибута eventPhase события event значение CAPTURING_PHASE.
      3. Вызов со struct, event, "capturing" и legacyOutputDidListenersThrowFlag, если он задан.
   14. Для каждой структуры struct в пути события event:
      1. Если цель с корректировкой тени структуры struct не равна null, тогда установите для атрибута eventPhase события event значение AT_TARGET.
      2. В противном случае,
         1. Если атрибут bubbles события event имеет значение false, продолжайте.
         2. Установите для атрибута eventPhase события event значение BUBBLING_PHASE.
      3. Вызовите с помощью struct, event, «bubbling» и legacyOutputDidListenersThrowFlag, если он задан.
6. Установите для атрибута eventPhase события event значение NONE.
7. Установите для атрибута currentTarget события event значение null.
8. Установите путь события event в пустой список.
9. Снять флаг отправки события event, флаг остановки распространения и флаг остановки немедленного распространения.
10. Если clearTargets, ????? то:
   1. Установите для цели события event значение null.
   2. Установите для параметра relatedTarget события event значение null.
   3. Установите список сенсорных целей события event в пустой список.
11. Если activationTarget не равно null, то:
   1. Если флаг отмены события event не установлен, запустите поведение активации activateTarget с событием event.
   2. В противном случае, если у activationTarget есть устаревшее отменённое поведение активации, запустите устаревшее отменённое поведение активации activationTarget.
12. Верните false, если установлен флаг отмены события event, и true в противном случае.

 

Чтобы «добавить к пути события» (append to an event path), учитывая event, invocationTarget, shadowAdjustedTarget, relatedTarget, touchTargets и slot-in-closed-tree, выполните следующие действия:

1. Пусть invocationTargetInShadowTree будет ложным.
2. Если invocationTarget является узлом, а его корень - теневым корнем, установите invocationTargetInShadowTree в значение true.
3. Пусть root-of-closed-tree будет false.
4. Если invocationTarget является теневым корнем, режим которого "closed", то установите для root-of-closed-tree значение true.
5. Добавьте новую структуру к пути события event, цель вызова которого - invocationTarget, цель вызова в теневом дереве - invocationTargetInShadowTree, цель с корректировкой тени - shadowAdjustedTarget, relatedTarget - relatedTarget, список целевых объектов касания - touchTargets, корень закрытого дерева - root-of-closed-tree, а слот в закрытом дереве - slot-in-closed-tree.

 

Чтобы «вызвать» (invoke), учитывая структуру struct, событие event, фазу phase и необязательный legacyOutputDidListenersThrowFlag, выполните следующие действия:

1. Задайте цель события event равной цели с корректировкой тени последней структуры в пути события event, то есть либо структурой struct, либо предыдущей структурой struct, чья цель с корректировкой тени не равна null.
2. Установите relatedTarget события event на relatedTarget структуры struct.
3. Задайте для списка цели касания события event - список цели касания структуры struct.
4. Если установлен флаг остановки распространения события event, вернитесь.
5. Инициализируйте атрибут currentTarget события event для цели вызова структуры struct.
6. Пусть слушатели listeners будут клоном из списка слушателей событий значения атрибута currentTarget.
Примечание Это позволяет избежать запуска слушателей событий, добавленных после этого момента. Обратите внимание, что удаление по-прежнему действует из-за удаленного поля.
7. Пусть invocationTargetInShadowTree будет целью вызова в теневом дереве структуры struct.
8. Пусть "найденный" found будет результатом выполнения внутреннего вызова с событием event, слушателями listeners, фазой phase, invocationTargetInShadowTree и legacyOutputDidListenersThrowFlag, если он задан.
9. Если "найденный" found - ложь, а атрибут isTrusted события event - истина, то:
   1. Пусть originalEventType будет значением атрибута type события event.
   2. Если значение атрибута type события event совпадает с любой из строк в первом столбце следующей таблицы, установите значение атрибута type события event равным строке во втором столбце той же строки, что и соответствующая строка, и вернитесь в противном случае.
Event type Legacy event type
«animationend» «webkitAnimationEnd»
«animationiteration» «webkitAnimationIteration»
«animationstart» «webkitAnimationStart»
«transitionend» «webkitTransitionEnd»
   3. Внутренний вызов с event, listeners, phase, invocationTargetInShadowTree, и legacyOutputDidListenersThrowFlag, если он задан. 
   4. Установите для атрибута type события event значение исходного типа события originalEventType.

 

Для «внутреннего вызова» (inner invoke) с учетом event, listeners, phase, invocationTargetInShadowTree и необязательного legacyOutputDidListenersThrowFlag выполните следующие действия:

1. Пусть found будет false.
2. Для каждого слушателя listener в слушателях listeners, у которого удалено значение false:
   1. Если значение атрибута type события event не является типом слушателя listener, тогда продолжайте.
   2. Установите found на true.
   3. Если фаза phase является "capturing", а захват слушателя listener ложный, тогда продолжайте.
   4. Если фаза phase "bubbling", а захват слушателя listener - истина, тогда продолжайте.
   5. Если значение "однажды" слушателя listener равно true, тогда удалите listener из списка слушателей событий значения атрибута currentTarget события event.
   6. Пусть global будет глобальным объектом связанной области Realm, с обратным вызовом слушателя listener.
   7. Пусть currentEvent будет неопределенным - undefined.
   8. Если global - это объект Window, то:
      1. Установите currentEvent на текущее событие global.
      2. Если invocationTargetInShadowTree установлено значение false, установите текущее событие global как событие event.
   9. Если пассивность слушателя listener - это истина, то установите флаг пассивного слушателя в событии event.
   10. Вызов операции пользовательского объекта с помощью обратного вызова слушателя listener, "handleEvent", «event» и значения атрибута currentTarget события event. Если это вызывает исключение, то:
      1. Сообщите об исключении.
      2. Установите legacyOutputDidListenersThrowFlag, если он указан.
      Примечание legacyOutputDidListenersThrowFlag используется только Indexed Database API. [INDEXEDDB]
   11. Сбросить в пассивный флаг слушателя событие event.
   12. Если global является объектом Window, установите текущее событие global на currentEvent.
   13. Если установлен флаг немедленного прекращения распространения события event, возвращается found.
3. Вернуть found

 

2.10 Запуск событий

Чтобы «запустить событие» (fire an event) с именем «e» в цели target, при необходимости используя eventConstructor, с описанием того, как должны быть инициализированы атрибуты IDL, и устаревшим флагом переопределения цели (legacy target override flag), выполните следующие действия:

1. Если eventConstructor не указан, пусть eventConstructor будет Event.
2. Пусть событие event будет результатом создания события, заданного eventConstructor, в соответствующей области цели target.
3. Инициализировать атрибут type события event как "e".
4. Инициализируйте любые другие IDL-атрибуты события event, как описано при вызове этого алгоритма.
   Примечание Это также позволяет установить для атрибута isTrusted значение false.
5. Вернуть результат отправки события event в цель target с флагом переопределения цели (legacy target override flag), если он установлен.

Примечание Запуск в контексте DOM — это сокращение от создания, инициализации и отправки события. Запуск события упрощает запись этого процесса.

 

Примеры

Если событию нужно инициализировать атрибуты bubbles или cancelable, можно написать «запустить событие с именем submit на цели target с его атрибутом cancelable, инициализированным значением true».

Или, когда требуется настраиваемый конструктор, «запускайте событие с именем click на цели target, используя MouseEvent с его атрибутом detail, инициализированным равным 1».

Иногда важно возвращаемое значение:

1. Пусть doAction будет результатом запуска события с именем like в target.
2. Если doAction истинно, то…

 

2.11 Действие против события

Событие означает происшествие, а не действие. Другими словами, он представляет собой уведомление от алгоритма и может использоваться для влияния на будущий ход этого алгоритма ( например, посредством вызова preventDefault() ). События не должны использоваться в качестве действий или инициаторов, вызывающих запуск какого-либо алгоритма. Они не для этого.

Примечание Это вызвано здесь специально, потому что в предыдущих итерациях DOM была концепция «действий по умолчанию», связанных с событиями, которые давали людям все неправильные идеи. События не представляют и не вызывают действия, их можно использовать только для влияния на текущее.

 

3 Прерывание текущей деятельности

Хотя обещания (Promise) не имеют встроенного механизма прерывания, многие API, использующие их, требуют семантики прерывания. AbortController предназначен для поддержки этих требований, предоставляя метод abort(), который переключает состояние соответствующего объекта AbortSignal. API, который хочет поддерживать прерывание, может принять объект AbortSignal и использовать его состояние, чтобы определить, как действовать дальше.

API, которые полагаются на AbortController, рекомендуется реагировать на abort(), отклоняя любое невыполненное обещание с помощью нового исключения DOMException «AbortError».

 

Пример

Гипотетический метод doAmazingness ({…}) может принимать объект AbortSignal для поддержки прерывания следующим образом:

const controller = new AbortController();
const signal = controller.signal;

startSpinner();

doAmazingness({ ..., signal })
   .then(result => ...)
   .catch(err => {
      if (err.name == 'AbortError') return;
      showUserErrorMessage();
   })
   .then(() => stopSpinner());

// …

controller.abort();

doAmazingness можно реализовать следующим образом:

function doAmazingness({signal}) {
   if (signal.aborted) {
      return Promise.reject(new DOMException('Aborted', 'AbortError'));
   }

   return new Promise((resolve, reject) => {
      // Begin doing amazingness, and call resolve(result) when done.
      // But also, watch for signals:
      signal.addEventListener('abort', () => {
         // Stop doing amazingness, and:
         reject(new DOMException('Aborted', 'AbortError'));
      });
   });
}

API-интерфейсы, требующие более детального управления, могут расширять объекты AbortController и AbortSignal в соответствии со своими потребностями.

 

3.1 Интерфейс AbortController (Прерывание контроллера)

IDL

[Exposed=( Window , Worker )]
interface AbortController {
   constructor();

   [SameObject] readonly attribute AbortSignal signal;

   undefined abort();
};

 

Для веб разработчиков (не нормативно)

controller = new AbortController()

Возвращает новый контроллер controller, signal которого установлен на вновь созданный объект AbortSignal.

controller . signal

Возвращает объект AbortSignal, связанный с этим объектом.

controller . abort()

Вызов этого метода установит флаг прерывания AbortSignal этого объекта и сигнализирует всем наблюдателям, что связанное действие должно быть прервано.

 

С объектом AbortController связан «сигнал» (signal) (объект AbortSignal).

Шаги конструктора new AbortController():

1. Пусть signal будет новым объектом AbortSignal.
2. Установите для сигнала этого this значение signal.

 

Шаги получателя сигнала signal должны вернуть сигнал этого this.

Шаги метода abort() должны сигнализировать об отмене сигнала этого this

 

3.2 Интерфейс AbortSignal (Прерывание сигнала)

IDL

[Exposed=( Window , Worker )]
interface AbortSignal : EventTarget {
   readonly attribute boolean aborted;

   attribute EventHandler onabort;
};

 

Для веб разработчиков (не нормативно)

signal . aborted

Возвращает true, если AbortController этого AbortSignal сигнализирует об отмене, и false в противном случае.

 

У объекта AbortSignal есть связанный «флаг прерывания» (aborted flag). Он не установлен, если не указано иное.

С объектом AbortSignal связаны «алгоритмы прерывания» (abort algorithms), которые представляют собой набор алгоритмов, которые должны выполняться, когда установлен его флаг прерывания. Если не указано иное, его значением является пустой набор.

 

Чтобы «добавить» (add) алгоритм algorithm к signal объекта AbortSignal, выполните следующие действия:

1. Если установлен флаг прерывания сигнала signal, вернитесь.
2. Добавить algorithm к алгоритмам прерывания сигнала signal.

 

Чтобы «удалить» (remove) алгоритм algorithm из сигнала AbortSignal, удалите algorithm из алгоритмов прерывания сигнала signal.

Примечание Алгоритмы прерывания позволяют API со сложными требованиями разумно реагировать на abort(). Например, флаг прерывания данного API может потребоваться распространить в среду с несколькими потоками, такую как сервис-воркер.

 

Шаги получателя aborted должны вернуть истину, если установлен прерванный флаг этого this; в противном случае — ложь.

Атрибут onabort — это IDL-атрибут обработчика событий для обработчика события onabort, чей тип события обработчика события — это abort.

Примечание Изменения в объекте AbortSignal представляют пожелания соответствующего объекта AbortController, но API, наблюдающий за объектом AbortSignal, может игнорировать их. Например, если операция уже завершена.

 

Чтобы «прервать сигнал» (signal abort), учитывая signal объекта AbortSignal, выполните следующие действия:

1. Если установлен флаг прерывания сигнала signal, вернитесь.
2. Установить флаг прерывания сигнала signal.
3. Для каждого алгоритма algorithm в алгоритмах прерывания сигнала signal: запустить algorithm.
4. Опустошить алгоритмы прерывания сигнала signal.
5. Запустить события с именем abort по сигналу signal.

 

Последующий сигнал followingSignal (AbortSignal) заставляется «следовать» (follow) за родительским сигналом parentSignal (AbortSignal), выполнив следующие шаги:

1. Если установлен флаг прерывания followingSignal, то вернитесь.
2. Если установлен флаг прерывания parentSignal, то сигнал прерывается при followingSignal.
3. В противном случае добавьте следующие шаги прерывания в parentSignal:
   1. Прерывание сигнала при followingSignal.

 

3.3 Использование объектов AbortController и AbortSignal в API

Любой API веб-платформы, использующий обещания для представления операций, которые можно прервать, должен соответствовать следующему:

  • Принимайте объекты AbortSignal через член словаря signal.
  • Сообщите, что операция была прервана из-за отклонения обещания с помощью исключения DOMException «AbortError».
  • Немедленно отклонить, если флаг прерывания AbortSignal уже установлен, в противном случае:
  • Используйте механизм прерывания алгоритмов, чтобы наблюдать за изменениями объекта AbortSignal и делать это таким образом, чтобы не приводить к конфликтам с другими наблюдателями.

 

Пример

Шаги для метода doAmazingness(options), возвращающего обещание, могут быть следующими:

1. Пусть p будет новым обещанием (promise).
2. Если присутствует элемент signal options, то:
   1. Если установлен флаг прерывания signal options, тогда отклоните p с помощью DOMException "AbortError" и верните p.
   2. Добавьте следующие шаги прерывания к signal options (сигналу опций):
      1. Прекратите делать удивительные вещи.
      2. Отклонить p с исключением DOMException "AbortError".
3. Выполните эти шаги параллельно:
   1. Пусть amazingResult станет результатом удивительных вещей.
   2. Разрешите p с amazingResult.
4. Верните p

 

API, не использующие обещания, по-прежнему должны в максимальной степени придерживаться вышеуказанного.

 

4 Узлы

4.1 Введение в «DOM»

В первоначальном смысле «DOM» — это API для доступа к документам (в частности, документами HTML и XML) и управления ими. В этой спецификации термин «документ» используется для любого ресурса на основе разметки, от коротких статических документов до длинных эссе или отчетов с богатым мультимедиа, а также до полноценных интерактивных приложений.

Каждый такой документ представлен в виде дерева узлов. У некоторых узлов дерева могут быть дети, тогда как другие всегда являются листьями.

Для иллюстрации рассмотрим этот HTML-документ:

<!DOCTYPE html>
<html class=e>
   <head><title>Aliens?</title></head>
   <body>Why yes.</body>
</html>

Он представлен следующим образом:

Структура дерева узлов
Структура дерева узлов

Обратите внимание, что из-за магии синтаксического анализа HTML не все пробелы ASCII были превращены в узлы Text, но общая концепция ясна. Разметка идет, дерево узлов выходит.

Примечание Для более подробного изучения этого вопроса можно использовать самый превосходный Live DOM Viewer.

 

4.2 Дерево узлов

Объекты Document, DocumentType, DocumentFragment, Element, Text, ProcessingInstruction и Comment (просто называемые «узлами» — nodes) участвуют в дереве, называемом просто «деревом узлов» (node tree).

Дерево узлов ограничено следующим образом, что выражается как отношение между типом узла и его разрешенными детьми:

Document

В древовидном порядке:

1. Ноль или более узлов, каждый из которых является инструкцией обработки ProcessingInstruction или комментарием Comment.

2. Необязательно один узел DocumentType.

3. Ноль или более узлов, каждый из которых является инструкцией обработки ProcessingInstruction или комментарием Comment.

4. Необязательно один узел Element.

5. Ноль или более узлов, каждый из которых является инструкцией обработки ProcessingInstruction или комментарием Comment.

DocumentFragment

Element

Ноль или более узлов, каждый из которых является Element, Text, ProcessingInstruction или Comment.

DocumentType

Text

ProcessingInstruction

Comment

Ничто

 

Чтобы определить «длину» (length) узла node, включите node:

DocumentType

Ноль

Text

ProcessingInstruction

Comment

Длина его данных.

Любой другой узел

Его количество детей

 

Узел считается «пустым» (empty), если его длина равна нулю.

 

4.2.1 Дерево документа

«Дерево документа» (document tree) — это дерево узлов, корнем которого является документ.

«Элемент документа» (document element) из документа — это элемент, чей родитель является этим документом, если он существует, и null в противном случае.

Примечание В соответствии с ограничениями дерева узлов такой элемент может быть только один.

 

Элемент находится «в дереве документа» (in a document tree), если его корнем является документ.

Элемент находится «в документе» (in a document), если он находится в дереве документа.

Примечание Термин в документе больше не должен использоваться. Это указывает на то, что стандарт его использования не был обновлен для учета теневых деревьев.

 

4.2.2 Теневое дерево

«Теневое дерево» (shadow tree) — это дерево узлов, корень которого является теневым корнем.

Теневой корень всегда присоединяется к другому дереву узлов через свой хост. Поэтому теневое дерево никогда не бывает одиноко. Дерево узлов хоста теневого корня иногда называют «светлым деревом» (light tree).

Примечание Соответствующее теневому дереву светлое дерево может быть самим теневым деревом.

Элемент является «связанным» (connected), если его корень, включающий тень, является документом.

 

4.2.2.1 Слоты

Теневое дерево содержит ноль или более элементов, являющихся «слотами» (slots).

Примечание Слот можно создать только с помощью элемента slot HTML.

У слота есть связанное «имя» (name) (строка). Если не указано иное, это пустая строка.

Чтобы обновить имя слота, выполните следующие действия по изменению атрибута:

1. Если element - это слот, localName - это name, а пространство имен namespace - null, то:
   1. Если значение value является старым значением oldValue, вернитесь.
   2. Если значение value равно нулю, а oldValue - пустая строка, вернитесь.
   3. Если значение value является пустой строкой, а oldValue имеет значение null, вернитесь.
   4. Если значение value равно null или пустая строка, тогда установите имя элемента element в пустую строку.
   5. В противном случае установите для имени элемента element значение value.
   6. Запустите назначить таблицы слотов для дерева с корнем элемента element.

 

Примечание! Первый слот в теневом дереве в порядке дерева, имя которого — пустая строка, иногда называют «слотом по умолчанию».

 

Слот имеет связанные «назначенные узлы» (assigned nodes) (список таблиц слотов). Если не указано иное, он пуст.

 

4.2.2.2 Таблицы слотов

Узлы Element и Text — это «таблицы слотов» (slottables).

Примечание Слот может быть таблицей слотов.

Таблица слотов имеет связанное «имя» (name) (строку). Если не указано иное, это пустая строка.

Используйте следующие шаги изменения атрибута, чтобы обновить имя таблицы слотов:

1. Если localName - это slot, а пространство имен namespace - null, то:
   1. Если значение value является oldValue, вернитесь.
   2. Если значение value равно null, а oldValue - пустая строка, вернитесь.
   3. Если значение value является пустой строкой, а oldValue имеет значение null, вернитесь.
   4. Если значение value равно null или пустая строка, тогда установите имя элемента element в пустую строку.
   5. В противном случае, установите для имени элемента element значение value.
   6. Если элемент element является назначенным, выполните команду назначения таблицы слотов для назначенного слота элемента element.
   7. Запустите назначение слота для элемента element.

 

Таблица слотов имеет связанный «назначенный слот» (assigned slot) (null или слот). Если не указано иное, он null. Таблица слотов назначается, если «назначенный» (assigned) ей слот не равен null.

 

4.2.2.3 Поиск слотов и таблиц слотов

Чтобы «найти слот» (find a slot) для данной таблицы слотов slottable и необязательного флага открытия — open flag (не установленного, если не указано иное), выполните следующие действия:

1. Если родитель slottable имеет значение null, вернуть значение null.
2. Пусть тень shadow будет теневым корнем родителя slottable.
3. Если тень shadow равна null, вернуть null.
4. Если установлен флаг открытия open flag и режим тени shadow не not "open", вернуть null.
5. Верните первый слот в древовидной структуре потомков shadow, чьим именем является имя таблицы слотов slottable, если оно есть, и null в противном случае.

 

Чтобы «найти таблицы слотов» (find slottables) для данного слота slot, выполните следующие действия:

1. Пусть result будет пустым списком.
2. Если корень слота slot не является теневым корнем, вернуть результат result.
3. Пусть host будет корневым хостом слота slot.
4. Для каждого ребёнка таблицы слотов из host, slottable в древовидном порядке:
   1. Пусть foundSlot будет результатом поиска слота в данной таблице слотов slottable.
   2. Если foundSlot - это slot, тогда к результату result добавьте таблицу слотов slottable.
5. Верните result.

 

Чтобы «найти плоские таблицы слотов» (find flattened slottables) для данного слота slot, выполните следующие действия:

1. Пусть result будет пустым списком.
2. Если корень slot не является теневым корнем, вернуть результат result.
3. Пусть slottables будут результатом поиска таблицы слотов для данного слота slot.
4. Если список slottables пустой, добавьте каждый ребёнка таблицы слотов из slot, в древовидном порядке к slottables.
5. Для каждого узла node в таблицах слотов slottables:
   1. Если узел node - это слот, корень которого является теневым корнем, то:
      1. Пусть временный результат temporaryResult будет результатом поиска сглаженных таблиц слотов для данного узла node.
      2. Добавьте каждую таблицу слотов во временный результат temporaryResult в порядке следования к result.
   2. В противном случае добавьте узел node к результату result.
6. Верните result.

 

4.2.2.4 Назначение таблиц слотов и слотов

Чтобы «назначить таблицы слотов» (assign slottables) для слота slot, выполните следующие действия:

1. Пусть slottables будет результатом поиска таблицы слотов для slot.
2. Если slottables и назначенные узлы slot не идентичны, тогда запустите сигнал на смену слота на slot.
3. Установите назначенные узлы слота slot в таблицы слотов slottables.
4. Для каждой slottable в slottables установите назначенный слот slottable на slot.

 

Чтобы «назначить таблицы слотов для дерева» (assign slottables for a tree), учитывая корень root узла, запустите назначение таблиц слотов для каждого слота slot во инклюзивных потомках корня root в древовидном порядке.

Чтобы «назначить слот» (assign a slot) с учетом таблицы слотов slottable, выполните следующие действия:

1. Пусть слот slot будет результатом поиска слота с slottable.
2. Если slot не null, запустите назначение таблицы слотов для слота slot.

 

4.2.2.5 Сигнализация об изменении слота

Каждый агент окна с одинаковым происхождением имеет «сигнальные слоты» (signal slots) (набор слотов), которые изначально пусты. [HTML]

Чтобы «сигнализировать об изменении слота» (signal a slot change), для слота slot выполните следующие действия:

1. Добавьте slot к сигнальным слотам соответствующего агента slot.
2. Поставить в очередь микрозадачу наблюдателя за мутациями.

 

4.2.3 Алгоритмы мутации

Чтобы «обеспечьте правильность предварительной вставки» (ensure pre-insertion validity) узла node в родителя parent перед ребёнком child, выполните следующие действия:

1. Если родитель parent не является узлом Document, DocumentFragment или Element, генерируется исключение DOMException "HierarchyRequestError".
2. Если узел node является включающим в себя хост предка родителя parent, то генерирует исключение DOMException "HierarchyRequestError".
3. Если ребёнок child не равен null, а его родитель не является parent, бросить исключение DOMException "NotFoundError".
4. Если узел node не является узлом DocumentFragment, DocumentType, Element, Text, ProcessingInstruction или Comment, то выбросить исключение DOMException "HierarchyRequestError".
5. Если какой-либо узел node является текстовым узлом Text, а родитель parent - документом, или узел node является типом документа, а родитель parent не является документом, то генерируется исключение DOMException "HierarchyRequestError".
6. Если parent является документом, и любое из приведенных ниже операторов, включенных на узле node, истинно, то бросить DOMException "HierarchyRequestError".
   Узел DocumentFragment
      Если узел node имеет более одного ребёнка элемента или имеет ребёнка узел Text.
      В противном случае, если узел node имеет одного ребёнка элемент, а у любого из родителей parent есть ребёнок элемент, child является типом документа или child не равен null, а тип документа следует за child.
   Элемент
      parent имеет ребёнка элемент, child - это тип документа, или child не равно null, а тип документа следует за child.
   Тип документа
      parent имеет ребёнка тип документа, child не равен null и элемент предшествует child, или child имеет значение null, а parent имеет ребёнка элемент.

 

Чтобы «предварительно вставить» (pre-insert) узел node в родителя parent перед ребёнком child, выполните следующие действия:

1. Обеспечьте правильность предварительной вставки узла node в родителя parent перед ребёнком child.
2. Пусть referenceChild будет child.
3. Если referenceChild является узлом node, тогда установите referenceChild на узел node следующего родственника (брата/сестры).
4. Вставить узел node в родителя parent перед referenceChild.
5. Вернуть node

 

Спецификации могут определять «шаги вставки» (insertion steps) для всех или некоторых узлов. Алгоритм передается insertedNode, как указано в алгоритме вставки ниже.

Спецификации могут определять «шаги изменения детей» (children changed steps) для всех или некоторых узлов. Алгоритм не передает аргументов и вызывается из данных вставки, удаления и замены.

 

Чтобы «вставить» (insert) узел node в родителя parent перед ребёнком child, с «необязательным флагом подавления наблюдателей» (suppress observers flag), выполните следующие действия:

1. Пусть узлы nodes будут детьми node, если узел node является узлом DocumentFragment; иначе «node».
2. Пусть count будет размером узлов nodes.
3. Если count равен 0, вернитесь.
4. Если узел node является узлом DocumentFragment, то:
   1. Удалите его детей с установленным "флагом подавления наблюдателей" (suppress observers flag).
   2. Поставить в очередь запись мутации дерева для узла node с «», узлами nodes, null и null. (??????)
   Примечание Этот шаг намеренно не обращает внимания на "флаг подавления наблюдателей" (suppress observers flag).
5. Если ребёнок child не равен null, то:
   1. Для каждого активного диапазона, у которого начальный узел является родителем parent, а начальное смещение больше, чем индекс child, увеличьте его начальное смещение на count.
   2. Для каждого активного диапазона, у которого конечный узел является родителем parent, а конечное смещение больше, чем индекс child, увеличьте его конечное смещение на count.
6. Пусть previousSibling будет предыдущим родственником child или последним ребёнком родителя parent, если child имеет значение null.
7. Для каждого узла node в узлах nodes в древовидном порядке:
   1. Добавить узел node в узел документа parent.
   2. Если ребёнок child равен null, добавьте узел node к детям родителя parent.
   3. В противном случае вставьте узел node в детей родителя parent перед индексом child.
   4. Если родитель parent является теневым хостом, а узел node - таблицей слотов, тогда назначьте слот для узла node.
   5. Если корень родителя parent является теневым корнем, а родитель parent - это слот, чьи назначенные узлы являются пустым списком, то запустите сигнал об изменении слота для родителя parent.
   6. Запустите команду назначения таблицы слотов для дерева с корнем узла node.
   7. Для каждого включающего тень инклюзивного потомка, inclusiveDescendant узла node, в древовидном порядке, включающем тень:
      1. Выполните шаги вставки с помощью inclusiveDescendant.
      2. Если подключен inclusiveDescendant, то:
         1. Если inclusiveDescendant является настраиваемым, то поставьте в очередь реакцию обратного вызова настраиваемого элемента с inclusiveDescendant, именем обратного вызова "connectedCallback" и пустым списком аргументов.
         2. В противном случае, попробуйте обновить inclusiveDescendant.
         Примечание Если это успешно обновляет inclusiveDescendant, его "connectedCallback" будет автоматически поставлен в очередь во время алгоритма обновления элемента.
8. Если "флаг подавления наблюдателей" (suppress observers flag) не установлен, то поставить в очередь запись мутации дерева для родителя parent с узлами nodes, «», previousSibling и child.
9. Запустите шаги изменения детей для родителя parent.

 

Чтобы «добавить» (append) узел node к родителю parent, предварительно вставьте узел node в родителя parent до null.

 

Чтобы «заменить» (replace) ребёнка child на узел node в родителе parent, выполните следующие действия:

1. Если parent не является узлом Document, DocumentFragment или Element, генерируется исключение DOMException "HierarchyRequestError".
2. Если узел node является включающим в себя хост предком родителя parent, то генерирует исключение DOMException "HierarchyRequestError".
3. Если родитель child не является parent, генерирует исключение DOMException "NotFoundError".
4. Если узел node не является узлом DocumentFragment, DocumentType, Element, Text, ProcessingInstruction или Comment, то генерирует DOMException "HierarchyRequestError".
5. Если какой-либо узел node является текстовым узлом Text, а родитель parent - документом, или узел node является типом документа, а parent не является документом, то генерируется исключение DOMException "HierarchyRequestError".
6. Если parent является документом, и любое из приведенных ниже операторов, включенных на узле node, истинно, то генерирует DOMException "HierarchyRequestError".
   Узел DocumentFragment
      Если узел node имеет более одного ребёнка элемента или имеет ребёнка узел Text.
      В противном случае, если у узла node есть один ребёнок элемент и у любого из родителей parent есть ребёнок элемент, который не является child, или тип документа следует за child.
   элемент
      parent имеет ребёнка элемент, который не является child, или тип документа следует за child.
   тип документа
      parent имеет ребёнка тип документа, который не является child, или элемент предшествует child.
   Примечание! Приведенные выше утверждения отличаются от алгоритма предварительной вставки.
7. Пусть referenceChild будет следующим родственником (братом/сестрой) ребенка child.
8. Если referenceChild является узлом node, тогда установите referenceChild на узел следующего родственника node.
9. Пусть previousSibling будет предыдущим родственником (братом/сестрой) ребенка child.
10. Пусть removeNodes будет пустым набором.
11. Если родитель ребенка child не равен null, тогда:
   1. Установите значение removeNodes на « child ».
   2. Удалите child с установленным "флагом подавления наблюдателей" (suppress observers flag).
   Примечание! Вышеупомянутое может быть ложным, только если child является node.
12. Пусть узлы nodes будут детьми node, если узел node является узлом DocumentFragment; иначе « node ».
13. Вставить узел node в родителя parent перед referenceChild с установленным "флагом подавления наблюдателей" (suppress observers flag).
14. Поставьте в очередь запись мутации дерева для родителя parent с помощью узлов nodes, removedNodes, previousSibling и referenceChild.
15. Вернуть child

 

Чтобы «заменить все» (replace all) с узлом node в родителе parent, выполните следующие действия:

1. Пусть удаленные узлы removedNodes будут детьми родителя parent.
2. Пусть addedNodes будет пустым набором.
3. Если node является узлом DocumentFragment, тогда установите addedNodes для детей node.
4. В противном случае, если node не равен null, установите addedNodes в «node».
5. Удалите всех детей родителя parent в порядке дерева с установленным "флагом подавления наблюдателей" (suppress observers flag).
6. Если узел не равен null, вставьте узел node в родителя parent до нуля(null) с установленным "флагом подавления наблюдателей" (suppress observers flag).
7. Если параметр addedNodes или deletedNodes не пуст, то поставить в очередь запись мутации дерева для родителя parent с дополнительными узлами addedNodes, удаленными узлами deletedNodes, нулевым(null) и нулевым (null) значениями. ?????

Примечание! Этот алгоритм не выполняет никаких проверок в отношении ограничений дерева узлов. Авторам спецификации нужно использовать это с умом.

 

Чтобы «предварительно удалить» (pre-remove) ребенка child из родителя parent, выполните следующие действия:

1. Если родитель child не является parent, выбросить исключение DOMException "NotFoundError".
2. Удалить ребенка child
3. Вернуть ребенка child

 

Спецификации могут определять «шаги удаления» (removing steps) для всех или некоторых узлов. Алгоритм передается removeNode и, возможно, oldParent, как указано в алгоритме удаления ниже.

 

Чтобы «удалить» (remove) узел node с необязательным «флагом подавления наблюдателей» (suppress observers flag), выполните следующие действия:

1. Пусть родитель parent будет родителем узла node
2. Утверждение: parent не равен нулю (null).
3. Пусть index будет индексом узла node.
4. Для каждого активного диапазона, начальный узел которого является инклюзивным потомком узла node, установите его начало в (parent, index).
5. Для каждого активного диапазона, конечный узел которого является инклюзивным потомком узла node, установите его конец в (parent, index).
6. Для каждого активного диапазона, начальный узел которого является parent, а начальное смещение больше index, уменьшите его начальное смещение на 1.
7. Для каждого активного диапазона, конечный узел которого является parent, а конечное смещение больше index, уменьшите его конечное смещение на 1.
8. Для каждого объекта NodeIterator, iterator, чей документ узла корня которого является документом узла node, запустите NodeIterator, предварительно удалив шаги для данного узла node и итератора iterator.
9. Пусть oldPreviousSibling будет предыдущим родственником узла node.
10. Пусть oldNextSibling будет следующим родственником узла node.
11. Удалите узел node из детей его родителя parent.
12. Если узел node назначен, запустите назначение таблиц слотов для назначенного слота узла node.
13. Если корень родителя parent является теневым корнем, а parent - это слот, чьи назначенные узлы являются пустым списком, запустите сигнал об изменении слота для родителя parent.
14. Если у узла node есть инклюзивный потомок, который является слотом, то:
   1. Запустите назначение таблиц слотов для дерева с корнем родителя parent.
   2. Запустите назначение таблиц слотов для дерева с узлом node.
15. Выполните шаги удаления с узлом node и родителем parent.
16. Пусть isParentConnected будет подключен к родителю parent.
17. Если node является настраиваемым и isParentConnected имеет значение true, то поставьте в очередь реакцию обратного вызова настраиваемого элемента с помощью node, имени обратного вызова «disconnectedCallback» и пустого списка аргументов.
   Примечание! На данный момент это намеренно, что настраиваемые элементы не передаются parent. Это может измениться в будущем, если возникнет необходимость.
18. Для каждого потомка узла, включающего тень, descendant из node, в порядке дерева, включающего тень, затем:
   1. Выполните шаги удаления с потомком descendant.
   2. Если потомок descendant является настраиваемым, а isParentConnected имеет значение true, то поставить в очередь реакцию обратного вызова настраиваемого элемента с потомком descendant, именем обратного вызова «disconnectedCallback» и пустым списком аргументов.
19. Для каждого инклюзивного предка inclusiveAncestor родителя parent, а затем для каждого зарегистрированного registered из списка зарегистрированных наблюдателей inclusiveAncestor, если поддерево subtree параметров зарегистрированного registered истинно, затем добавьте нового временного зарегистрированного наблюдателя, наблюдатель которого является наблюдателем registered, параметры являются параметрами registered, а источник является registered в список зарегистрированных наблюдателей узла node.
20. Если "флаг подавления наблюдателей" (suppress observers flag) не установлен, то поставить в очередь запись мутации дерева для родителя parent с «», « node », oldPreviousSibling и oldNextSibling.
21. Запустите шаги изменения детей для родителя.

 

 

4.2.4 Смешивание NonElementParentNode (Неэлементный родительский узел)

Примечание! Веб-совместимость предотвращает отображение метода getElementById() в элементах (и, следовательно, в ParentNode).

IDL
interface mixin NonElementParentNode {
   Element? getElementById(DOMString elementId);
};
Document includes NonElementParentNode;
DocumentFragment includes NonElementParentNode;

Для веб-разработчиков (не нормативно)!

node . getElementById(elementId)

Возвращает первый элемент среди потомков узла node, чей идентификатор IDelementId.

 

Метод getElementById(elementId) при вызове должен возвращать первый элемент в древовидном порядке внутри его потомков этого this, чей идентификатор ID — это elementId, и null, если в противном случае такого элемента нет.

 

4.2.5 Смешивание DocumentOrShadowRoot (Документ или теневой корень)

IDL

interface mixin DocumentOrShadowRoot {
};
Document includes DocumentOrShadowRoot;
ShadowRoot includes DocumentOrShadowRoot;

Примечание! Предполагается, что миксин DocumentOrShadowRoot будет использоваться другими стандартами, которые хотят определять API, общие для документов и теневых корней.

 

4.2.6 Смешивание ParentNode (Родительский узел)

Чтобы «преобразовать узлы в узел» (convert nodes into a node) с учетом узлов nodes и документа document, выполните следующие действия:

1. Пусть узел node будет нулевым (null).
2. Замените каждую строку в узлах nodes новым узлом Text, данными которого является строка, а узлом документа является document.
3. Если узлы nodes содержат один узел, установите node на этот узел.
4. В противном случае установите для узла node новый DocumentFragment, чей документ узла является документом document, а затем добавьте к нему каждый узел в узлах nodes, если таковые имеются.
5. Верните node

 

IDL

interface mixin ParentNode {
   [SameObject] readonly attribute HTMLCollection children;
   readonly attribute Element? firstElementChild;
   readonly attribute Element? lastElementChild;
   readonly attribute unsigned long childElementCount;

   [CEReactions, Unscopable] undefined prepend((Node or DOMString)... nodes);
   [CEReactions, Unscopable] undefined append((Node or DOMString)... nodes);
   [CEReactions, Unscopable] undefined replaceChildren((Node or DOMString)... nodes);

   Element? querySelector(DOMString selectors);
   [NewObject] NodeList querySelectorAll(DOMString selectors);
};
Document includes ParentNode;
DocumentFragment includes ParentNode;
Element includes ParentNode;

 

Для веб-разработчиков (ненормативный)

collection = node . children

Возвращает детей элементы (детей).

element = node . firstElementChild

Возвращает первого ребёнка, который является элементом, в противном случае — null.

element = node . lastElementChild

Возвращает последнего ребёнка, который является элементом, в противном случае — null.

node . prepend(nodes)

Вставляет узлы nodes перед первым ребёнком узла node, заменяя строки в узлах nodes эквивалентными текстовыми узлами Text.

Выбрасывает исключение DOMException «HierarchyRequestError«, если нарушаются ограничения дерева узлов.

node . append(nodes)

Вставляет узлы nodes после последнего ребёнка узла node, заменяя строки в узлах nodes эквивалентными текстовыми узлами Text.

Выбрасывает исключение DOMException «HierarchyRequestError«, если нарушаются ограничения дерева узлов.

node . replaceChildren(nodes)

Замените всех детей узла node узлами nodes, заменяя строки в узлах nodes эквивалентными узлами Text.

Выбрасывает исключение DOMException «HierarchyRequestError«, если нарушаются ограничения дерева узлов.

node . querySelector(selectors)

Возвращает первый элемент, являющийся потомком узла node, соответствующего selectors.

node . querySelectorAll(selectors)

Возвращает все элементы потомки узла node, соответствующие селекторам selectors.

 

Получатель атрибута children должен возвращать коллекцию HTMLCollection, основанную на этом this совпадающем только элементом ребёнка.

Получатель атрибута firstElementChild должен возвращать первого ребёнка, который является элементом, в противном случае — null.

Получатель атрибута lastElementChild должен возвращать последнего ребёнка, который является элементом, в противном случае — null.

Получатель атрибута childElementCount должен возвращать количество детей этого this, которые являются элементами.

 

При вызове метода prepend(nodes) необходимо выполнить следующие шаги:

1. Пусть узел node будет результатом преобразования узлов в узел с учетом узлов nodes и документа узла этого this.
2. Предварительно вставьте node в этот this перед первым ребёнком этого this.

 

При вызове метода append(nodes) необходимо выполнить следующие шаги:

1. Пусть узел node будет результатом преобразования узлов в узел с учетом узлов nodes и документа узла этого this.
2. Добавьте узел node к этому this.

 

При вызове метода replaceChildren(nodes) необходимо выполнить следующие шаги:

1. Пусть узел node будет результатом преобразования узлов в узел с учетом узлов nodes и документа узла этого this.
2. Убедитесь, что узел node действителен перед вставкой в этот this до нуля(null).
3. Замените все узлом node внутри этого this.

 

Метод querySelector(selectors) при вызове должен возвращать первый результат выполнения сопоставления области видимости строковых селекторов selectors для этого this, если результат не является пустым списком, и null в противном случае.

Метод querySelectorAll(selectors) при вызове должен возвращать статический результат выполнения сопоставления области видимости строковых селекторов selectors для этого this.

 

4.2.7 Смешивание NonDocumentTypeChildNode (Дочерний узел не типа документа)

Примечание! Веб-совместимость предотвращает отображение атрибутов previousElementSibling и nextElementSibling в типах документов (и, следовательно, в ChildNode).

IDL

interface mixin NonDocumentTypeChildNode {
readonly attribute Element? previousElementSibling;
readonly attribute Element? nextElementSibling;
};
Element includes NonDocumentTypeChildNode;
CharacterData includes NonDocumentTypeChildNode;

 

Для веб-разработчиков (не нормативно)

element = node . previousElementSibling

Возвращает первого предшествующего родственника, который является элементом, в противном случае — null.

element = node . nextElementSibling

Возвращает первого следующего родственника, который является элементом, в противном случае — null.

 

Получатель атрибута previousElementSibling должен возвращать первого предшествующего родственника, который является элементом, в противном случае — null.

Получатель атрибута nextElementSibling должен возвращать первого следующего родственника, который является элементом, в противном случае — null.

 

4.2.8 Смешивание ChildNode (Дочерний узел)

IDL

interface mixin ChildNode {
   [CEReactions, Unscopable] undefined before((Node or DOMString)... nodes);
   [CEReactions, Unscopable] undefined after((Node or DOMString)... nodes);
   [CEReactions, Unscopable] undefined replaceWith((Node or DOMString)... nodes);
   [CEReactions, Unscopable] undefined remove();
};
DocumentType includes ChildNode;
Element includes ChildNode;
CharacterData includes ChildNode;

 

Для веб-разработчиков (не нормативно)

node . before(…nodes)

Вставляет узлы nodes непосредственно перед узлом node, заменяя строки в узлах nodes эквивалентными текстовыми узлами Text.

Выбрасывает исключение DOMException «HierarchyRequestError«, если нарушаются ограничения дерева узлов.

node . after(…nodes)

Вставляет узлы nodes сразу после узла node, заменяя строки в узлах nodes эквивалентными текстовыми узлами Text.

Выбрасывает исключение DOMException «HierarchyRequestError«, если нарушаются ограничения дерева узлов.

node . replaceWith(…nodes)

Заменяет узел node узлами nodes, заменяя строки в узлах nodes эквивалентными текстовыми узлами Text.

Выбрасывает исключение DOMException «HierarchyRequestError«, если нарушаются ограничения дерева узлов.

node . remove()

Удаляет узел node.

 

При вызове метода before(nodes) необходимо выполнить следующие шаги:

1. Пусть родитель parent будет родителем этого this.
2. Если parent имеет значение null, вернитесь.
3. Пусть viablePreviousSibling будет первым предшествующим родственником этого this не в узлах nodes, в противном случае - null.
4. Пусть узел node будет результатом преобразования узлов в узел, учитывая узлы nodes и документ узла этого this.
5. Если viablePreviousSibling имеет значение null, установите для него значение первого ребёнка родителя parent, а в противном случае - значение следующего родственника  viablePreviousSibling.
6. Предварительно вставьте узел node в родителя parent перед viablePreviousSibling.

 

При вызове метода after(nodes) необходимо выполнить следующие шаги:

1. Пусть родитель parent будет родителем этого this.
2. Если parent имеет значение null, вернитесь.
3. Пусть viableNextSibling будет первым следующим родственником этого this, не находящимся в узлах nodes, в противном случае - null.
4. Пусть узел node будет результатом преобразования узлов в узел, учитывая узлы nodes и документ узла этого this.
5. Предварительно вставьте узел node в родителя parent перед viableNextSibling.

 

При вызове метода replaceWith(nodes) необходимо выполнить следующие шаги:

1. Пусть родитель parent будет родителем этого this.
2. Если parent имеет значение null, вернитесь.
3. Пусть viableNextSibling будет первым следующим родственником этого this, не находящимся в узлах nodes, в противном случае - null.
4. Пусть узел node будет результатом преобразования узлов в узел, учитывая узлы nodes и документ узла этого this.
5. Если родитель этого this является parent, замените this на узел node в родителе parent.
   Примечание! Этот this может быть вставлен в узел node.
6. В противном случае предварительно вставьте узел node в родителя parent перед viableNextSibling.

 

При вызове метода remove() необходимо выполнить следующие действия:

1. Если родитель этого this имеет значение null, вернитесь.
2. Удалите этот this.

 

4.2.9 Смешивание Slottable (Таблица слотов)

IDL

interface mixin Slottable {
   readonly attribute HTMLSlotElement? assignedSlot;
};
Element includes Slottable;
Text includes Slottable;

1

Получатель атрибута assignSlot должен возвращать результат поиска слота с учетом этого this и с установленным флагом открытия (open flag).

 

4.2.10 Коллекции в старом стиле: NodeList и HTMLCollection

«Коллекция» (collection) — это объект, представляющий список узлов. Коллекция может быть как «живой/активной» (live), так и «статической» (static). Если не указано иное, коллекция должна быть живой.

Если коллекция активна (жива), то атрибуты и методы этого объекта должны работать с фактическими базовыми данными, а не с моментальным снимком данных.

При создании коллекции с ней связываются фильтр и корень.

Затем коллекция «представляет» (represents) вид корневого поддерева как корень коллекции, содержащее только узлы, соответствующие заданному фильтру. Вид линейный. При отсутствии особых требований об обратном, узлы в коллекции должны быть отсортированы в древовидном порядке.

 

4.2.10.1 Интерфейс NodeList (Список узлов)

Объект NodeList — это коллекция узлов.

IDL

[Exposed=Window]
interface NodeList {
   getter Node? item(unsigned long index);
   readonly attribute unsigned long length;
   iterable<Node>;
};

 

Для веб-разработчиков (не нормативно)

collection . length

Возвращает количество узлов в коллекции.

element = collection . item(index)

element = collection[index]

Возвращает узел с индексом index из коллекции. Узлы отсортированы в древовидном порядке.

 

Индексы поддерживаемых свойств объекта — это числа в диапазоне от нуля до количество узлов минус один, представленных коллекцией. Если таких элементов нет, то индексы поддерживаемых свойств отсутствуют.

Атрибут length должен возвращать количество узлов, представленных коллекцией.

Метод item(index) должен возвращать indexный узел в коллекции. Если в коллекции нет indexного узла, метод должен возвращать значение null.

 

4.2.10.2 Интерфейс HTMLCollection (Коллекция HTML)

IDL

[Exposed=Window, LegacyUnenumerableNamedProperties]
interface HTMLCollection {
   readonly attribute unsigned long length;
   getter Element? item(unsigned long index);
   getter Element? namedItem(DOMString name);
};

Объект HTMLCollection — это коллекция элементов.

Примечание! HTMLCollection — это исторический артефакт, от которого сеть не может избавиться. Хотя разработчики, конечно, могут продолжать его использовать, разработчики новых стандартов API не должны его использовать (вместо этого используйте sequence<T> в IDL).

 

Для веб-разработчиков (не нормативно)

collection . length

Возвращает количество элементов в коллекции.

element = collection . item(index)

element = collection[index]

Возвращает элемент с индексом index из коллекции. Элементы отсортированы в древовидном порядке.

element = collection . namedItem(name)

element = collection[name]

Возвращает первый элемент с идентификатором или именем name из коллекции.

 

Индексы поддерживаемых свойств объекта — это числа в диапазоне от нуля до количества элементов минус один, представленных коллекцией. Если таких элементов нет, то индексы поддерживаемых свойств отсутствуют.

Получатель атрибута length должен возвращать количество узлов, представленных коллекцией.

При вызове метода item(index) он должен возвращать indexный элемент в коллекции. Если в коллекции нет indexного элемента, метод должен возвращать значение null.

 

Имена поддерживаемых свойств — это значения из списка, возвращаемого этими шагами:

1. Пусть result будет пустым списком.
2. Для каждого элемента element, представленного коллекцией, в древовидном порядке:
   1. Если элемент element имеет идентификатор ID, которого нет в результате result, добавьте идентификатор ID элемента element к результату result.
   2. Если элемент element находится в пространстве имен HTML и имеет атрибут имени name, значение которого не является ни пустой строкой, ни результатом result, добавьте значение атрибута имени name элемента element к результату result.
3. Верните result

 

При вызове метода namedItem(key) необходимо выполнить следующие действия:

1. Если ключ key - это пустая строка, верните ноль(null).
2. Вернуть первый элемент в коллекции, для которого верно хотя бы одно из следующего:
   - у него есть ID, который является ключом key;
   - он находится в пространстве имен HTML и имеет атрибут имени name, значение которого является ключом key;

или null, если такого элемента нет.

 

4.3 Наблюдатели за мутациями

Каждый оконный агент с одинаковым происхождением имеет «в очереди микрозадачу наблюдателя мутаций» (mutation observer microtask queued)(логическое значение — boolean), которая изначально является ложной (false). [HTML]

Каждый оконный агент с одинаковым происхождением также имеет «наблюдателей мутаций» (mutation observers) (набор из нуля или более объектов MutationObserver), которые изначально пусты.

Чтобы «поставить в очередь микрозадачу наблюдателя за мутациями» (queue a mutation observer microtask), выполните следующие действия:

1. Если поставленная в очередь микрозадача наблюдателя за мутациями окружающего агента верна (true), вернитесь.
2. Установите для поставленной в очередь микрозадачи наблюдателя за мутациями окружающего агента значение true.
3. Поставьте в очередь микрозадачу для уведомления наблюдателей за мутациями.

 

Чтобы «уведомить наблюдателей за мутациями» (notify mutation observers), выполните следующие действия:

1. Установите для поставленной в очередь микрозадачи наблюдателя за мутациями окружающего агента значение false.
2. Пусть notifySet будет клоном наблюдателей мутаций окружающего агента.
3. Пусть signalSet будет клоном сигнальных слотов окружающего агента.
4. Освободите сигнальные слоты окружающего агента.
5. Для каждого наблюдателя мутаций mo из notifySet:
   1. Пусть записи records будут клоном очереди записей mo.
   2. Очистите очередь записей mo.
   3. Для каждого узла node из списка узлов mo, удалите всех временных зарегистрированных наблюдателей, наблюдателем которых является mo, из списка зарегистрированных наблюдателей узла node.
   4. Если записи records не пустые, вызовите обратный вызов mo с «records, mo» и mo. Если это вызывает исключение, сообщите об исключении.
6. Для каждого слота slot из signalSet, запустите событие с именем slotchange с его атрибутом bubbles (пузырьков), установленным в значение true, в slot.

 

Каждый узел имеет «список зарегистрированных наблюдателей» (registered observer list) (список из нуля или более зарегистрированных наблюдателей), который изначально пуст.

«Зарегистрированный наблюдатель» (registered observer) состоит из «наблюдателя» (observer) (объект MutationObserver) и «параметров» (options) (словарь MutationObserverInit).

«Временный зарегистрированный наблюдатель» (transient registered observer) — это зарегистрированный наблюдатель, который также состоит из «источника» (source) (зарегистрированного наблюдателя).

Примечание! Временные зарегистрированные наблюдатели используются для отслеживания мутаций в потомках данного узла после того, как узел был удален, чтобы они не терялись, когда поддерево subtree имеет значение true для родителя узла.

 

4.3.1 Интерфейс MutationObserver (Наблюдатель за мутациями)

IDL

[Exposed=Window]
interface MutationObserver {
   constructor(MutationCallback callback);

   undefined observe(Node target, optional MutationObserverInit options = {});
   undefined disconnect();
   sequence<MutationRecord> takeRecords();
};

callback MutationCallback = undefined (sequence<MutationRecord> mutations, MutationObserver observer);

dictionary MutationObserverInit {
   boolean childList = false;
   boolean attributes;
   boolean characterData;
   boolean subtree = false;
   boolean attributeOldValue;
   boolean characterDataOldValue;
   sequence<DOMString> attributeFilter;
};

Объект MutationObserver может использоваться для наблюдения за мутациями дерева узлов.

С каждым объектом MutationObserver связаны следующие концепции:

  • «Обратный вызов» (callback), установленный при создании.
  • «Список узлов» (node list) (список узлов), который изначально пуст.
  • «Очередь записей» (record queue) (очередь из нуля или более объектов MutationRecord), которая изначально пуста.

 

Для веб-разработчиков (не нормативно)

observer = new MutationObserver(callback)

Создает объект MutationObserver и устанавливает его обратный вызов в callback. Обратный вызов callback вызывается со списком объектов MutationRecord в качестве первого аргумента и созданного объекта MutationObserver в качестве второго аргумента. Он вызывается после мутации узлов, зарегистрированных методом наблюдения observe().

observer . observe(target, options)

Дает указание пользовательскому агенту наблюдать за заданной целью target (узел) и сообщать о любых мутациях на основе критериев, заданных параметрами options (объектом).

Аргумент options позволяет устанавливать параметры наблюдения за мутациями через участников объекта. Вот участники объекта, которые можно использовать:

childList

Установите значение true, если нужно наблюдать за мутациями детей цели target.

attributes

Установите значение true, если необходимо наблюдать за мутациями атрибутов цели target. Может быть опущено, если указан attributeOldValue или attributeFilter.

characterData

Установите значение true, если необходимо наблюдать мутации в данных цели target. Может быть опущено, если указан characterDataOldValue.

subtree

Установите значение true, если необходимо наблюдать мутации не только для цели target, но и для ее потомков.

attributeOldValue

Установите значение true, если атрибуты attributes истинны или опущены, а значение атрибута цели target перед изменением необходимо записать.

characterDataOldValue

Установите значение true, если для characterData задано значение true или опущено, а данные цели target до мутации необходимо записать.

attributeFilter

Установите в список локальных имен атрибутов (без пространства имен), если не все атрибуты мутаций необходимо соблюдать и attributes истинны или опущены.

observer . disconnect()

Останавливает observer от наблюдения за любыми мутациями. До тех пор, пока снова не будет использован метод наблюдения observe(), обратный вызов observer не будет вызываться.

observer . takeRecords()

Очищает очередь записей и возвращает то, что там было.

 

При вызове конструктора MutationObserver(callback) необходимо выполнить следующие действия:

1. Пусть mo будет новым объектом MutationObserver, обратным вызовом которого является callback.
2. Добавить mo к наблюдателям мутаций соответствующего агента mo.
3. Вернуть mo.

 

При вызове метода наблюдения observe(target, options) должны выполняться следующие шаги:

1. Если параметр attributeOldValue или attributeFilter options присутствует, а параметр «attributes» options опущен, то установите для параметра «attributes» options значение true.
2. Если параметр characterDataOldValue options присутствует, а параметр characterData options опущен, установите для параметра characterData options значение true.
3. Если ни один из параметров options - childList, attributes и characterData не является истинным, то выдает ошибку TypeError.
4. Если для параметра options attributeOldValue установлено значение true, а для attributes options установлено значение false, генерировать ошибку TypeError.
5. Если параметр options attributeFilter присутствует, а attributes options имеют значение false, генерировать ошибку TypeError.
6. Если параметр options characterDataOldValue имеет значение true, а параметр options characterData - false, то выдает ошибку TypeError.
7. Для каждой зарегистрированной registered из списка зарегистрированных наблюдателей цели target, если наблюдатель registered это this:
   1. Для каждого узла node из списка узлов этого this удалите всех временных зарегистрированных наблюдателей, источник которых является registered из списка зарегистрированных наблюдателей узла node.
   2. Установите параметры registered на options.
8. Иначе:
   1. Добавьте нового зарегистрированного наблюдателя, чей наблюдатель это this, а опции - это options в список зарегистрированных наблюдателей цели target.
   2. Добавить цель target в список узлов этого this.

 

При вызове метода disconnect() необходимо выполнить следующие действия:

1. Для каждого узла node в списке узлов этого this, удалите любого зарегистрированного наблюдателя из списка зарегистрированных наблюдателей узла node, для которого this является наблюдателем.
2. Очистите очередь записей этого this.

 

При вызове метода takeRecords() необходимо выполнить следующие действия:

1. Пусть записи records будут клоном очереди записей этого this.
2. Очистите очередь записей этого this.
3. Верните records

 

4.3.2 Организация очереди записи мутации

Чтобы «поставить в очередь запись мутации» (queue a mutation record) типа type для цели target с именем name, пространством имен namespace, старым значением oldValue, добавленными узлами addedNodes, удалёнными узлами removedNodes, предыдущим родственником previousSibling и последующим родственником nextSibling, выполните следующие действия:

1. Пусть interestedObservers будет пустой картой.
2. Пусть узлы nodes будут инклюзивными предками цели target.
3. Для каждого узла node в узлах nodes, а затем для каждого зарегистрированного registered из списка зарегистрированных наблюдателей узла node:
   1. Пусть options будут вариантами registered.
   2. Если ничего из следующего не верно
      узел node не является target, а поддерево subtree опций options ложно
      type является "attributes" и атрибуты attributes опций options не являются истиной
      type является "attributes", параметр attributeFilter опций options присутствует, и attributeFilter опций не содержит имени name или пространство имен namespace не равно null
      type является "characterData", а characterData опций options не являются истиной
      type является "childList", а childList опций options ложно

   Тогда
      1. Пусть mo будет наблюдателем registered.
      2. Если interestedObservers[mo] не существует, то установите interestedObservers[mo] в значение null.
      3. Если любой из type имеет значение "attributes", а параметр attributeOldValue опций options - true, либо type - "characterData", а параметр characterDataOldValue опций options - true, тогда задайте interestedObservers[mo] значение oldValue.

4. Для каждого наблюдателя observermappedOldValue из interestedObservers:
   1. Пусть запись record будет новым объектом MutationRecord с типом type, установленным на type, target установленным на target, attributeName установленным на name, attributeNamespace установленным на namespace, oldValue установленным на mappedOldValue, addedNodes установленным на addedNodes, removedNodes установлен на removedNodes, previousSibling установлен на previousSibling, и nextSibling установлен на nextSibling.
   2. Поставить запись record в очередь записей наблюдателя observer.
5. Поставить в очередь микрозадачу наблюдателя за мутациями.

 

Чтобы «поставить в очередь запись мутации дерева» (queue a tree mutation record) для цели target с добавленными узлами addedNodes, удаленными узлами removedNodes, previousSibling и nextSibling, выполните следующие действия:

1. Утверждение: либо addedNodes, либо removeNodes не пусто.
2. Поместите в очередь запись мутации "childList" для цели target с null, null, null, addedNodes, removedNodes, previousSibling и nextSibling.

 

4.3.3 Интерфейс MutationRecord (Запись мутации)

IDL

[Exposed=Window]
interface MutationRecord {
   readonly attribute DOMString type;
   [SameObject] readonly attribute Node target;
   [SameObject] readonly attribute NodeList addedNodes;
   [SameObject] readonly attribute NodeList removedNodes;
   readonly attribute Node? previousSibling;
   readonly attribute Node? nextSibling;
   readonly attribute DOMString? attributeName;
   readonly attribute DOMString? attributeNamespace;
   readonly attribute DOMString? oldValue;
};

 

Для веб-разработчиков (не нормативно)

record . type

Возвращает «attributes«, если это было изменение атрибута. «characterData«, если это была мутация узла CharacterData. И «childList«, если это была мутация дерева узлов.

record . target

Возвращает узел, на котором произошла мутация, в зависимости от типа type. Для «attributes» это элемент, атрибут которого изменился. Для «characterData» это узел CharacterData. Для «childList» это узел, чьи дети изменились.

record . addedNodes

Возвращает добавленные узлы.

record . removedNodes

Возвращает удаленные узлы.

record . previousSibling

Возвращает предыдущего родственника добавленных или удаленных узлов соответственно, в противном случае — null.

record . nextSibling

Возвращает следующего родственника добавленных или удаленных узлов соответственно, в противном случае — null.

record . attributeName

Возвращает локальное имя измененного атрибута, в противном случае — null.

record . attributeNamespace

Возвращает пространство имен измененного атрибута, в противном случае — null.

record . oldValue

Возвращаемое значение зависит от типа type. Для «attributes» это значение измененного атрибута до изменения. Для «characterData» это данные измененного узла до изменения. Для «childList» это ноль.

 

Атрибуты type, target, addedNodes, removedNodes, previousSibling, nextSibling, attributeName, attributeNamespace, и oldValue должны возвращать значения, которыми они были инициализированы.

 

4.3.4 Сборка мусора

Узлы имеют явные ссылки на зарегистрированных наблюдателей в их списках зарегистрированных наблюдателей.

Зарегистрированные наблюдатели в списке зарегистрированных наблюдателей узла имеют слабую ссылку на узел.

 

4.4 Интерфейс Node (Узел)

IDL

[Exposed=Window]
interface Node : EventTarget {
   const unsigned short ELEMENT_NODE = 1;
   const unsigned short ATTRIBUTE_NODE = 2;
   const unsigned short TEXT_NODE = 3;
   const unsigned short CDATA_SECTION_NODE = 4;
   const unsigned short ENTITY_REFERENCE_NODE = 5; // исторический
   const unsigned short ENTITY_NODE = 6; // исторический
   const unsigned short PROCESSING_INSTRUCTION_NODE = 7;
   const unsigned short COMMENT_NODE = 8;
   const unsigned short DOCUMENT_NODE = 9;
   const unsigned short DOCUMENT_TYPE_NODE = 10;
   const unsigned short DOCUMENT_FRAGMENT_NODE = 11;
   const unsigned short NOTATION_NODE = 12; // исторический
   readonly attribute unsigned short nodeType;
   readonly attribute DOMString nodeName;

   readonly attribute USVString baseURI;

   readonly attribute boolean isConnected;
   readonly attribute Document? ownerDocument;
   Node getRootNode(optional GetRootNodeOptions options = {});
   readonly attribute Node? parentNode;
   readonly attribute Element? parentElement;
   boolean hasChildNodes();
   [SameObject] readonly attribute NodeList childNodes;
   readonly attribute Node? firstChild;
   readonly attribute Node? lastChild;
   readonly attribute Node? previousSibling;
   readonly attribute Node? nextSibling;

   [CEReactions] attribute DOMString? nodeValue;
   [CEReactions] attribute DOMString? textContent;
   [CEReactions] undefined normalize();

   [CEReactions, NewObject] Node cloneNode(optional boolean deep = false);
   boolean isEqualNode(Node? otherNode);
   boolean isSameNode(Node? otherNode); // исторический псевдоним ===

   const unsigned short DOCUMENT_POSITION_DISCONNECTED = 0x01;
   const unsigned short DOCUMENT_POSITION_PRECEDING = 0x02;
   const unsigned short DOCUMENT_POSITION_FOLLOWING = 0x04;
   const unsigned short DOCUMENT_POSITION_CONTAINS = 0x08;
   const unsigned short DOCUMENT_POSITION_CONTAINED_BY = 0x10;
   const unsigned short DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
   unsigned short compareDocumentPosition(Node other);
   boolean contains(Node? other);

   DOMString? lookupPrefix(DOMString? namespace);
   DOMString? lookupNamespaceURI(DOMString? prefix);
   boolean isDefaultNamespace(DOMString? namespace);

   [CEReactions] Node insertBefore(Node node, Node? child);
   [CEReactions] Node appendChild(Node node);
   [CEReactions] Node replaceChild(Node node, Node child);
   [CEReactions] Node removeChild(Node child);
};

dictionary GetRootNodeOptions {
   boolean composed = false;
};

 

Примечание! Node — это абстрактный интерфейс и не существует как узел. Он используется всеми узлами (Document, DocumentType, DocumentFragment, Element, Text, ProcessingInstruction и Comment).

 

Каждый узел имеет связанный «документ узла» (node document), установленный при создании, то есть документ.

 

Примечание! Документ узла узла может быть изменен с помощью алгоритма принятия.

 

Алгоритм получения родителя узла при наличии события event, возвращает назначенный слот узла, если узел назначен, и родитель узла в противном случае.

 

Примечание! У каждого узла также есть список зарегистрированных наблюдателей.

 

Для веб-разработчиков (не нормативно)

node . nodeType

Возвращает тип узла node, представленный числом из следующего списка:

Node . ELEMENT_NODE (1)

узел node — это элемент.

Node . TEXT_NODE (3)

узел node — это текстовый узел Text.

Node . CDATA_SECTION_NODE (4)

узел node — это узел CDATASection.

Node . PROCESSING_INSTRUCTION_NODE (7)

узел node — это узел ProcessingInstruction.

Node . COMMENT_NODE (8)

узел node — это узел комментария Comment.

Node . DOCUMENT_NODE (9)

узел node — это документ.

Node . DOCUMENT_TYPE_NODE (10)

узел node — это тип документа.

Node . DOCUMENT_FRAGMENT_NODE (11)

узел node — это узел DocumentFragment.

 

node . nodeName

Возвращает строку, соответствующую типу узла node, как показано ниже:

Element

Его полное имя в верхнем регистре HTML.

Attr

Его полное имя.

Text

«#text».

CDATASection

«#cdata-section».

ProcessingInstruction

Его цель.

Comment

«#comment».

Document

«#document».

DocumentType

Его имя.

DocumentFragment

«#document-fragment».

Получатель атрибута nodeType при вызове должен возвращать первый соответствующий оператор, включая этот this:

Element

ELEMENT_NODE (1)

Attr

ATTRIBUTE_NODE (2);

Text

TEXT_NODE (3);

CDATASection

CDATA_SECTION_NODE (4);

ProcessingInstruction

PROCESSING_INSTRUCTION_NODE (7);

Comment

COMMENT_NODE (8);

Document

DOCUMENT_NODE (9);

DocumentType

DOCUMENT_TYPE_NODE (10);

DocumentFragment

DOCUMENT_FRAGMENT_NODE (11).

 

Получатель атрибута nodeName при вызове должен возвращать первый соответствующий оператор, включая этот this:

Element

Его полное имя в верхнем регистре HTML.

Attr

Его полное имя.

Text

«#text».

CDATASection

«#cdata-section».

ProcessingInstruction

Его цель.

Comment

«#comment».

Document

«#document».

DocumentType

Его имя.

DocumentFragment

«#document-fragment».

 

Для веб-разработчиков (не нормативно)

node . baseURI

Возвращает базовый URL документа документа узла node

 

Получатель атрибута baseURI должен возвращать базовый URL документа документа узла, сериализованный.

 

Для веб-разработчиков (не нормативно)

node . isConnected

Возвращает true, если узел node подключен, и false в противном случае.

node . ownerDocument

Возвращает документ узла. Возвращает null для документов.

node . getRootNode()

Возвращает корень узла node.

node . getRootNode({ composed:true })

Возвращает, включающий тень, корень узла node.

node . parentNode

Возвращает родителя.

node . parentElement

Возвращает родительский элемент.

node . hasChildNodes()

Возвращает, есть ли у узла node дети.

node . childNodes

Возвращает детей.

node . firstChild

Возвращает первого ребенка.

node . lastChild

Возвращает последнего ребенка.

node . previousSibling

Возвращает предыдущего родственника.

node . nextSibling

Возвращает следующего родственника.

 

Получатель атрибута isConnected должен возвращать true, если этот this подключен, и false в противном случае.

Получатель атрибута ownerDocument должен возвращать null, если этот this является документом, и в противном случае — документ узла этого this.

 

Примечание! Документ узла документа — это сам этот документ. У всех узлов всегда есть документ узла.

Метод getRootNode(options) при вызове, должен возвращать корень, включающий тень этого this если composed параметров options истинно, и корень этого this в противном случае.

Получатель атрибута parentNode должен возвращать родителя этого this.

Примечание! Узел Attr не имеет родителя.

Получатель атрибута parentElement должен возвращать родительский элемент этого this.

Метод hasChildNodes() при вызове должен возвращать true, если у него (этого this) есть дети, и false в противном случае.

Получатель атрибута childNodes должен возвращать NodeList с корнем только для этого this совпадающих детей.

Получатель атрибута firstChild должен возвращать первого ребёнка этого this.

Получатель атрибута lastChild должен возвращать последнего ребёнка этого this.

Получатель атрибута previousSibling должен возвращать предыдущего родственника этого this.

Примечание! Узел Attr не имеет родственников.

Получатель атрибута nextSibling должен возвращать следующего родственника этого this.

 

В зависимости от этого атрибут nodeValue должен возвращать следующее:

Attr

значение этого this.

Text

ProcessingInstruction

Comment

данные этого this.

Любой другой узел

Null.

 

Атрибут nodeValue должен при установке, если новое значение равно null, действовать так, как если бы это была пустая строка, а затем делать, как описано ниже, в зависимости от этого this:

Attr

Установите существующее значение атрибута с этим this и новым значением.

Text

ProcessingInstruction

Comment

Замените данные узла этого this, смещение 0, посчитайте длину этого this и данные нового значение.

Любой другой узел

Ничего не делать.

 

Получатель атрибута textContent должен возвращать следующее, включая это:

DocumentFragment

Element

Текстовое содержимое потомка этого this.

Attr

значение этого this.

Text

ProcessingInstruction

Comment

данные этого this.

Любой другой узел

Null.

 

Чтобы «заменить все строкой» (string replace all) на строку string в узле parent, выполните следующие действия:

1. Пусть node будет null.
2. Если строка string не является пустой строкой, тогда установите узел node в новый текстовый узел Text, данные которого являются строкой string, а документ узла - это документ узла родителя parent.
3. Замените все на узел node в родителe parent.

 

Установщик атрибута textContent должен, если заданное значение равно null, действовать так, как если бы это была пустая строка, а затем сделать, как описано ниже, включив этот this:

DocumentFragment

Element

Заменить все строкой указанным значением этого this.

Attr

Установите существующее значение атрибута с этим this и новым значением.

Text

ProcessingInstruction

Comment

Замените данные узлом this, смещением 0, посчитайте длину this и передайте заданное значение.

Любой другой узел

Ничего не делать.

 

Для веб-разработчиков (не нормативно)

node . normalize()

Удаляет пустые эксклюзивные текстовые узлы Text и объединяет данные оставшихся смежных эксклюзивных текстовых узлов Text в первый из их узлов.

Метод normalize() при вызове должен выполнять эти шаги для каждого потомка эксклюзивного узла Text узла node этого this:

1. Пусть длина length будет длиной узла node.
2. Если длина length равна нулю, тогда удалите узел node и перейдите к следующему эксклюзивному узлу Text, если таковой имеется.
3. Пусть данные data будут объединением данных смежных эксклюзивных текстовых узлов Text узла node (исключая его самого) в древовидном порядке.
4. Замените данные узлом узла node, длиной смещения length, счетчиком 0 и данными данных data.
5. Пусть currentNode будет следующим родственником узла node.
6. Пока currentNode является эксклюзивным текстовым узлом Text:
   1. Для каждого живого диапазона, начальным узлом которого является currentNode, добавьте длину length к его начальному смещению и установите для его начального узла значение node.
   2. Для каждого активного диапазона, конечным узлом которого является currentNode, добавьте длину length к его конечному смещению и установите для его конечного узла значение node.
   3. Для каждого живого диапазона, чей начальный узел является родителем currentNode, а начальное смещение - индексом currentNode, установите для его начального узла значение node, а его начальное смещение - length.
   4. Для каждого активного диапазона, конечный узел которого является родителем currentNode, а конечное смещение - индексом currentNode, установите его конечный узел равным node, а его конечное смещение равным длине length.
   5. Добавьте длину currentNode к длине length.
   6. Установите currentNode на его следующего родственника.
7. Удалите смежные эксклюзивные текстовые узлы Text узла node (исключая его самого) в порядке дерева.

 

Для веб-разработчиков (не нормативно)

node . cloneNode([deep = false])

Возвращает копию узла node. Если deeptrue, копия также включает потомков узла node.

node . isEqualNode(otherNode)

Возвращает, имеют ли node и otherNode одинаковые свойства.

 

Спецификации могут определять «шаги клонирования» (cloning steps) для всех или некоторых узлов. Алгоритму передается копия copy, узел node, документ document и необязательный флаг клонирования детей (clone children flag), как указано в алгоритме клонирования.

Примечание! HTML определяет шаги клонирования для скриптов script и элементов ввода input. SVG должен делать то же самое со своими элементами скрипта script, но в данный момент не вызывает этого.

 

Чтобы «клонировать» (clone) узел node с дополнительным документом document и флагом клонирования детей (clone children flag), выполните следующие действия:

1. Если документ document не указан, пусть document будет документом узла node.
2. Если узел node является элементом, то:
   1. Пусть копия copy будет результатом создания элемента, заданного документа document, локального имени узла node, пространства имен узла node, префикса пространства имен узла node и значения is узла node, при снятом флаге синхронных настраиваемых элементов (synchronous custom elements flag).
   2. Для каждого атрибута attribute в списке атрибутов узла node:
      1. Пусть copyAttribute будет клоном attribute.
      2. Добавьте атрибут copyAttribute к копии copy.
3. В противном случае пусть copy будет узлом, который реализует те же интерфейсы, что и node, и выполняет эти дополнительные требования, включая узел node:
   Document
      Установите кодировку копии copy, тип контента, URL, источник, тип и режим, как для узла node.
   DocumentType
      Установите имя копии copy, общедоступный идентификатор и идентификатор системы, как для узла node.
   Attr
      Установите пространство имен копии copy, префикс пространства имен, локальное имя и значение как для узла node.
   Text
   Comment
      Установите данные копии copy на данные узла node.
   ProcessingInstruction
      Установите цель копии copy и данные для узла node.
   Любой другой узел
      —
4. Установите документ узла копии copy и document на copy, если copy является документом, и установите документ узла копии copy на document в противном случае.
5. Выполните все шаги клонирования, определенные для узла node в других применимых спецификациях, и передайте копию copy, узел node, документ document и флаг клонирования детей (clone children flag), если он установлен, в качестве параметров.
6. Если установлен флаг клонирования детей (clone children flag), клонируйте всех детей узла node и добавьте их для copy с document как указано и установленным флагом клонирования детей (clone children flag).
7. Вернуть copy

 

При вызове метода cloneNode(deep) необходимо выполнить следующие действия:

1. Если этот this является теневым корнем, выбросить исключение DOMException "NotSupportedError".
2. Верните клон этого this с установленным флагом clone children flag, если deep равен true.

 

Узел A «равен» (equals) узлу B, если выполняются все следующие условия:

Значение атрибута nodeType для A и B идентично.
Следующие значения также равны, в зависимости от A:
   DocumentType
      Его имя, публичный идентификатор и системный идентификатор.
   Element
      Его пространство имен, префикс пространства имен, локальное имя и размер его списка атрибутов.
   Attr
      Его пространство имен, локальное имя и значение.
   ProcessingInstruction
      Его цель и данные.
   Text
   Comment
      Его данные.
   Любой другой узел
      —
Если A является элементом, каждый атрибут в его списке атрибутов имеет атрибут, равный атрибуту в списке атрибутов B.
У A и B одинаковое количество детей.
Каждый ребёнок A равен ребёнку B по тому же индексу.

 

Метод isEqualNode(otherNode) при вызове должен возвращать истину true, если otherNode не равен null, и этот this равен otherNode, и false в противном случае.

Метод isSameNode(otherNode) при вызове должен возвращать true, если otherNode является this, и false в противном случае.

 

Для веб-разработчиков (не нормативно)

node . compareDocumentPosition(other)

Возвращает битовую маску, указывающую положение other относительно узла node. Это биты, которые можно установить:

Node . DOCUMENT_POSITION_DISCONNECTED (1)

Устанавливается, когда узел node и other не находятся в одном дереве.

Node . DOCUMENT_POSITION_PRECEDING (2)

Устанавливается, когда other предшествует узлу node.

Node . DOCUMENT_POSITION_FOLLOWING (4)

Устанавливается, когда other следует за узлом node.

Node . DOCUMENT_POSITION_CONTAINS (8)

Устанавливается, когда other является предком узла node.

Node . DOCUMENT_POSITION_CONTAINED_BY (16, 10 в шестнадцатеричном формате)

Устанавливается, когда other является потомком узла node.

node . contains(other)

Возвращает истину true, если other является инклюзивным потомком узла node, и ложь false в противном случае.

 

Это константы, которые compareDocumentPosition() возвращает в виде маски:

  • DOCUMENT_POSITION_DISCONNECTED (1);
  • DOCUMENT_POSITION_PRECEDING (2);
  • DOCUMENT_POSITION_FOLLOWING (4);
  • DOCUMENT_POSITION_CONTAINS (8);
  • DOCUMENT_POSITION_CONTAINED_BY (16, 10 в шестнадцатеричном формате);
  • DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC (32, 20 в шестнадцатеричном формате).

При вызове метода compareDocumentPosition(other) необходимо выполнить следующие действия:

1. Если этот this является other, вернуть ноль.
2. Пусть node1 будет other, а node2 будет this.
3. Пусть attr1 и attr2 будут null.
4. Если node1 является атрибутом, установите для attr1 значение node1 и node1 для элемента attr1.
5. Если node2 является атрибутом, то:
   1. Установите attr2 на node2 и node2 на элемент attr2.
   2. Если attr1 и node1 не равны NULL, а node2 - node1, то:
      1. Для каждого attr в списке атрибутов node2:
         1. Если attr равно attr1, вернуть результат добавления DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC и DOCUMENT_POSITION_PRECEDING.
         2. Если attr равно attr2, вернуть результат добавления DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC и DOCUMENT_POSITION_FOLLOWING.
6. Если node1 или node2 имеет значение NULL или корень node1 не является корнем node2, тогда верните результат добавления DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, и либо DOCUMENT_POSITION_PRECEDING, либо DOCUMENT_POSITION_FOLLOWING вместе с этим ограничением согласовано.
Примечание! Возвращать ли DOCUMENT_POSITION_PRECEDING или DOCUMENT_POSITION_FOLLOWING обычно можно путем сравнения указателей. В реализациях JavaScript можно использовать кешированное значение Math.random().
7. Если node1 является предком node2 и attr1 имеет значение NULL, или node1 является node2, а attr2 не равно NULL, то вернуть результат добавления DOCUMENT_POSITION_CONTAINS в DOCUMENT_POSITION_PRECEDING.
8. Если node1 является потомком node2, а attr2 имеет значение null, или node1 является node2, а attr1 не равно NULL, тогда вернуть результат добавления DOCUMENT_POSITION_CONTAINED_BY в DOCUMENT_POSITION_FOLLOWING.
9. Если node1 предшествует node2, верните DOCUMENT_POSITION_PRECEDING.
Примечание! Из-за способа обработки атрибутов в этом алгоритме это приводит к тому, что атрибуты узла считаются предшествующими его детскими узлами, несмотря на то, что атрибуты не участвуют в дереве.
10. Вернуть DOCUMENT_POSITION_FOLLOWING.

 

Метод contains(other) при вызове должен возвращать true, если other является инклюзивным потомком этого this, и false в противном случае (в том числе, когда other имеет значение null).

 

Чтобы «найти префикс пространства имен» (locate a namespace prefix) для элемента element с помощью пространства имен namespace, выполните следующие действия:

1. Если пространство имен элемента element - это namespace, а его префикс пространства имен не равен null, то вернуть его префикс пространства имен.
2. Если элемент element имеет атрибут с префиксом пространства имен "xmlns", а значением является namespace, то возвращается локальное имя первого такого атрибута элемента element.
3. Если родительский элемент элемента element не равен null, то верните результат выполнения поиска префикса пространства имен для этого элемента, используя пространство имен namespace.
4. Вернуть null

 

Чтобы «найти пространство имен» (locate a namespace) для узла node с помощью префикса prefix, включите узел node:

Element
   1. Если его пространство имен не равно null, а его префикс пространства имен - prefix, то вернуть пространство имен.
   2. Если у него есть атрибут, пространство имен которого является пространством имен XMLNS, префиксом пространства имен является "xmlns", а локальное имя - prefix, или если prefix имеет значение NULL и у него есть атрибут, пространство имен которого является пространством имен XMLNS, префикс пространства имен является null и локальное имя равно "xmlns", то вернет его значение, если это не пустая строка, и null в противном случае.
   3. Если его родительский элемент имеет значение NULL, вернуть значение NULL.
   4. Вернуть результат выполнения поиска пространства имен в его родительском элементе с помощью prefix.
Document
   1. Если его элемент документа равен NULL, вернуть NULL.
   2. Вернуть результат выполнения поиска пространства имен в его элементе документа с помощью prefix.
DocumentType
DocumentFragment
   Вернуть null.
Attr
   1. Если его элемент равен NULL, вернуть NULL.
   2. Вернуть результат выполнения поиска пространства имен на его элементе с помощью prefix.
Любой другой узел
   1. Если его родительский элемент имеет значение NULL, вернуть значение NULL.
   2. Вернуть результат выполнения поиска пространства имен в его родительском элементе с помощью prefix.

 

Метод lookupPrefix(namespace) при вызове должен выполнить следующие шаги:

1. Если пространство имен namespace равно null или пустая строка, верните null.
2. Включите этот this:
   Element
      Вернуть результат поиска префикса пространства имен для него с помощью namespace.
   Document
      Возвращает результат поиска префикса пространства имен для его элемента документа, если его элемент документа не равен null, и null в противном случае.
   DocumentType
   DocumentFragment
      Вернуть null.
   Attr
      Вернуть результат поиска префикса пространства имен для его элемента, если его элемент не равен null, и null в противном случае.
   Любой другой узел
      Вернуть результат поиска префикса пространства имен для его родительского элемента, если его родительский элемент не равен null, и null в противном случае.

 

При вызове метода lookupNamespaceURI(prefix) необходимо выполнить следующие шаги:

1. Если prefix - это пустая строка, установите для нее значение null.
2. Верните результат выполнения поиска пространства имен для этого this с помощью prefix.

 

Метод isDefaultNamespace(namespace) при вызове должен выполнить следующие шаги:

1. Если пространство имен namespace является пустой строкой, установите для него значение null.
2. Пусть defaultNamespace будет результатом выполнения поиска пространства имен для этого this с помощью null.
3. Верните true, если defaultNamespace совпадает с namespace, и false в противном случае.

 

Метод insertBefore(node, child) при вызове должен возвращать результат предварительной вставки узла node в this перед ребёнком child.

Метод appendChild(node) при вызове должен возвращать результат добавления узла к this.

Метод replaceChild(node, child) при вызове должен возвращать результат замены ребёнка child на узел node внутри this.

Метод removeChild(child) при вызове должен возвращать результат предварительного удаления ребёнка child из this.

 

«Список элементов с квалифицированным именем qualifiedName» (list of elements with qualified name qualifiedName) для узла root — это HTMLCollection, возвращаемый следующим алгоритмом:

1. Если qualifiedName равно «*» (U+002A), вернуть HTMLCollection с корнем root, фильтр которого соответствует только элементам потомкам.
2. В противном случае, если документ узла root является документом HTML, вернуть HTMLCollection с корнем root, фильтр которого соответствует следующим элементам потомкам:
Пространство имен которого является пространством имен HTML, а полное имя - qualifiedName в нижнем регистре ASCII.
Пространство имен которого не not является пространством имен HTML, а полное имя - qualifiedName.
3. В противном случае верните HTMLCollection с корнем root, чей фильтр соответствует элементам-потомкам, чье полное имя - qualifiedName.

 

При вызове с тем же аргументом и до тех пор, пока тип документа узла root не изменился, может быть возвращен тот же объект HTMLCollection, который был возвращен предыдущим вызовом.

«Список элементов с пространством имен namespace и локальным именем localName» (list of elements with namespace namespace and local name localName) для узла root — это HTMLCollection, возвращаемая следующим алгоритмом:

1. Если пространство имен namespace является пустой строкой, установите для нее значение null.
2. Если и namespace, и localName равны «*» (U+002A), вернуть HTMLCollection с корнем, чей фильтр соответствует элементам-потомкам.
3. В противном случае, если namespace равно «*» (U+002A), вернуть HTMLCollection с корнем root, фильтр которого соответствует элементам-потомкам, локальное имя которых - localName.
4. В противном случае, если localName равно «*» (U+002A), вернуть HTMLCollection с корнем root, фильтр которого соответствует элементам-потомкам, пространство имен которых является namespace.
5. В противном случае верните HTMLCollection с корнем root, фильтр которого соответствует элементам-потомкам, пространство имен которых - namespace, а локальное имя - localName.

 

При вызове с теми же аргументами может быть возвращен тот же объект HTMLCollection, который был возвращен более ранним вызовом.

«Список элементов с именами классов classNames» (list of elements with class names classNames) для узла root — это HTMLCollection, возвращаемый следующим алгоритмом:

1. Пусть классы classes будут результатом запуска синтаксического анализатора упорядоченного набора на classNames.
2. Если классы classes - это пустой набор, верните пустой HTMLCollection.
3. Вернуть HTMLCollection с корнем root, фильтр которого соответствует элементам-потомкам, все классы которых находятся в classes.
Сравнение классов должно производиться без учета регистра в кодировке ASCII, если режим документа узла root установлен на "quirks" (причуды), и идентичным образом в противном случае.

 

При вызове с тем же аргументом может быть возвращен тот же объект HTMLCollection, который был возвращен предыдущим вызовом.

 

4.5 Интерфейс Document (Документ)

IDL

[Exposed=Window]
interface Document : Node {
   constructor();

   [SameObject] readonly attribute DOMImplementation implementation;
   readonly attribute USVString URL;
   readonly attribute USVString documentURI;
   readonly attribute DOMString compatMode;
   readonly attribute DOMString characterSet;
   readonly attribute DOMString charset; // исторический псевдоним .characterSet
   readonly attribute DOMString inputEncoding; // исторический псевдоним .characterSet
   readonly attribute DOMString contentType;

   readonly attribute DocumentType? doctype;
   readonly attribute Element? documentElement;
   HTMLCollection getElementsByTagName(DOMString qualifiedName);
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);

   [CEReactions, NewObject] Element createElement(DOMString localName, optional (DOMString or ElementCreationOptions) options = {});
   [CEReactions, NewObject] Element createElementNS(DOMString? namespace, DOMString qualifiedName, optional (DOMString or ElementCreationOptions) options = {});
   [NewObject] DocumentFragment createDocumentFragment();
   [NewObject] Text createTextNode(DOMString data);
   [NewObject] CDATASection createCDATASection(DOMString data);
   [NewObject] Comment createComment(DOMString data);
   [NewObject] ProcessingInstruction createProcessingInstruction(DOMString target, DOMString data);

   [CEReactions, NewObject] Node importNode(Node node, optional boolean deep = false);
   [CEReactions] Node adoptNode(Node node);

   [NewObject] Attr createAttribute(DOMString localName);
   [NewObject] Attr createAttributeNS(DOMString? namespace, DOMString qualifiedName);

   [NewObject] Event createEvent(DOMString interface); // исторический

   [NewObject] Range createRange();

   // NodeFilter.SHOW_ALL = 0xFFFFFFFF
   [NewObject] NodeIterator createNodeIterator(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
   [NewObject] TreeWalker createTreeWalker(Node root, optional unsigned long whatToShow = 0xFFFFFFFF, optional NodeFilter? filter = null);
};

[Exposed=Window]
interface XMLDocument : Document {};

dictionary ElementCreationOptions {
   DOMString is;
};

 

Узлы Document просто известны как «документы» (documents).

Каждый документ имеет связанную «кодировку» (encoding), «тип содержимого» (content type — строка), «URL» (URL), «источник» (origin), «тип» (type — «xml» или «html») и «режим» (mode — «no-quirks«, «quirks«, or «limited-quirks» («без причуд», «причуды» или «ограниченные причуды»)). [ENCODING] [URL] [HTML]

Если не указано иное, кодировка документа — это кодировка utf-8, тип контента — «application/xml», URL — «about: blank», источникнепрозрачный источник, тип — «xml», а его режим — «no-quirks«.

Документ называется «XML-документом» (XML document), если его тип — «xml», и «HTML-документом» (HTML document) в противном случае. Независимо от того, является ли документ HTML-документом или XML-документом, влияет на поведение определенных API.

Считается, что документ находится в «режиме без причуд» (no-quirks mode), если его режим «no-quirks«, в «режиме причуд» (quirks mode), если его режим «quirks«, и в «режиме с ограниченными причудами» (limited-quirks mode), если его режим «limited-quirks«.

 

Примечание!

Режим по умолчанию изменяется только для документов, созданных синтаксическим анализатором HTML на основе наличия, отсутствия или значения строки DOCTYPE, а также с помощью нового контекста просмотра (начальное «about:blank»). [HTML]

Режим без причуд изначально был известен как «стандартный режим», а режим с ограниченными причудами когда-то был известен как «почти стандартный режим». Они были переименованы, потому что их детали теперь определены стандартами. (И потому, что Ян Хиксон наложил вето на их оригинальные имена на том основании, что они бессмысленны.)

При заданном событии event алгоритм получения родителя документа возвращает null, если значение атрибута типа type события event равно «load» или документ не имеет контекста просмотра, а в противном случае — соответствующий глобальный объект документа.

 

Для веб-разработчиков (не нормативно)

document = new Document()

Возвращает новый документ.

document . implementation

Возвращает объект DOMImplementation документа document.

document . URL

document . documentURI

Возвращает URL документа document.

document . compatMode

Возвращает строку «BackCompat», если режим документа document — «quirks», и «CSS1Compat» в противном случае.

document . characterSet

Возвращает кодировку документа document.

document . contentType

Возвращает тип содержимого документа document.

Конструктор Document() при вызове должен возвращать новый документ, источником которого является источник документа Document, связанного с текущим глобальным объектом. [HTML]

Примечание!

В отличие от createDocument(), этот конструктор возвращает не объект XMLDocument, а документ (объект Document).

Получатель атрибута implementation (реализация) должен возвращать объект DOMImplementation, связанный с документом.

Получатель атрибута URL и получатель атрибута documentURI должны возвращать сериализованный URL.

Получатель атрибута compatMode должен возвращать «BackCompat«, если режим этого this «quirks«, и «CSS1Compat» в противном случае.

Получатель атрибута characterSet, получатель атрибута charset и получатель атрибута inputEncoding должны возвращать имя кодировки этого this.

Получатель атрибута contentType должен возвращать тип контента.

 

Для веб-разработчиков (не нормативно)

document . doctype

Возвращает doctype или null, если его нет.

document . documentElement

Возвращает элемент документа.

collection = document . getElementsByTagName(qualifiedName)

Если qualifiedName — «*», возвращает HTMLCollection всех элементов потомков.

В противном случае возвращает HTMLCollection всех элементовпотомков, чье полное имяqualifiedName. (Сопоставляет без учета регистра элементов в пространстве имен HTML в документе HTML.)

collection = document . getElementsByTagNameNS(namespace, localName)

Если namespace и localName равны «*», возвращает HTMLCollection всех элементовпотомков.

Если только namespace равно «*», возвращает HTMLCollection всех элементовпотомков, локальное имя которых — localName.

Если только localName имеет значение «*», возвращает HTMLCollection всех элементовпотомков, пространство имен которых является namespace.

В противном случае возвращает HTMLCollection всех элементовпотомков, пространство имен которых является namespace, а локальное имяlocalName.

collection = document . getElementsByClassName(classNames)

collection = element . getElementsByClassName(classNames)

Возвращает HTMLCollection элементов в объекте, для которого был вызван метод (документ или элемент), у которых есть все классы, заданные classNames. Аргумент classNames интерпретируется как список классов, разделенных пробелами.

 

Получатель атрибута doctype должен возвращать ребёнка документа, который является типом документа, в противном случае — null.

Получатель атрибута documentElement должен возвращать элемент документа.

Метод getElementsByTagName(qualifiedName) при вызове должен возвращать список элементов с полным именем qualifiedName для этого this.

 

Примечание!

Таким образом, в HTML-документе запись document.getElementsByTagName(«FOO») будет соответствовать элементам <FOO>, которые не находятся в пространстве имен HTML, и элементам <foo>, которые находятся в пространстве имен HTML, но не элементам <FOO>, которые находятся в пространство имен HTML.

 

Метод getElementsByTagNameNS(namespace, localName) при вызове должен возвращать список элементов с пространством имен namespace и локальным именем localName для этого this.

Метод getElementsByClassName(classNames) при вызове должен возвращать список элементов с именами классов classNames для этого this.

 

Пример

Учитывая следующий фрагмент XHTML:

<div id="example">
   <p id="p1" class="aaa bbb"/>
   <p id="p2" class="aaa ccc"/>
   <p id="p3" class="bbb ccc"/>
</div>

Вызов document.getElementById(«example»).getElementsByClassName(«aaa») вернет HTMLCollection с двумя параграфами p1 и p2 в нем.

Однако вызов getElementsByClassName(«ccc bbb») вернет только один узел, а именно p3. Вызов document.getElementById(«example»).getElementsByClassName(«bbb ccc «) вернет то же самое.

Вызов getElementsByClassName(«aaa,bbb») не вернет узлов; ни один из вышеперечисленных элементов не входит в класс aaa, bbb.

 

Для веб-разработчиков (не нормативно)

element = document . createElement(localName [, options])

Возвращает элемент с localName в качестве локального имени (если document является HTML-документом, localName переводится в нижний регистр). Пространство имен элемента — это пространство имен HTML, если document является документом HTML или тип содержимого документа document — «application/xhtml+xml», в противном случае — null.

Если localName не соответствует продукту Name, будет выброшено исключение DOMException «InvalidCharacterError».

При поставке параметры options is можно использовать для создания настраиваемого встроенного элемента.

element = document . createElementNS(namespace, qualifiedName [, options])

Возвращает элемент с пространством имен namespace. Его префиксом пространства имен будет все, что находится перед «:» (U+003E) в qualifiedName или null. Его локальным именем будет все, что находится после «:» (U+003E) в qualifiedName или qualifiedName.

Если localName не соответствует продукту Name, будет выброшено исключение DOMException «InvalidCharacterError».

Если выполняется одно из следующих условий, будет выброшено исключение DOMException «NamespaceError«:

localName не соответствует продукту QName.

Префикс пространства имен не равен null, а namespace — это пустая строка.

Префикс пространства имен — «xml», а namespace не является пространством имен XML.

qualifiedName или префикс пространства имен — «xmlns», а namespace не является пространством имен XMLNS.

namespace — это пространство имен XMLNS, и ни qualifiedName, ни префикс пространства имен не являются «xmlns».

При наличии опции options «is» можно использовать для создания настраиваемого встроенного элемента.

documentFragment = document . createDocumentFragment()

Возвращает узел DocumentFragment.

text = document . createTextNode(data)

Возвращает узел Text, данные которого являются data.

text = document . createCDATASection(data)

Возвращает узел CDATASection, данные которого являются data.

comment = document . createComment(data)

Возвращает узел комментария Comment, данные которого являются data.

processingInstruction = document . createProcessingInstruction(target, data)

Возвращает узел ProcessingInstruction, цель которого — target, а данныеdata. Если target не соответствует продукту Name, будет выброшено исключение DOMException «InvalidCharacterError». Если data содержат «?>», Будет выброшено исключение DOMException «InvalidCharacterError».

 

«Интерфейс элемента» (element interface) для любого имени name и пространства имен namespace является Element, если не указано иное.

 

Примечание!

Стандарт HTML будет, например, определите, что для html и пространства имен HTML используется интерфейс HTMLHtmlElement. [HTML]

Метод createElement(localName, options) при вызове должен выполнить следующие шаги:

1. Если localName не совпадает с производством Name, генерируется исключение DOMException «InvalidCharacterError».
2. Если этот this является документом HTML, установите для localName значение localName в нижнем регистре ASCII.
3. Пусть is будет null.
4. Если options - это словарь и is options присутствует, то установите is на него.
5. Пусть пространство имен namespace будет пространством имен HTML, если этот this является документом HTML или тип содержимого этого this - «application/xhtml+xml», и null в противном случае.
6. Вернуть результат создания элемента с учетом this, localName, namespace, null, is и с установленным флагом синхронных настраиваемых элементов (synchronous custom elements).

«Внутренние шаги createElementNS» (internal createElementNS steps) для данного документа document, пространства имен namespace, квалифицированного имени qualifiedName и параметров options следующие:

1. Пусть namespace, prefix и localName будут результатом передачи namespace и qualifiedName для проверки и извлечения.
2. Пусть is будет null.
3. Если options - это словарь и is options присутствует, то установите is на него.
4. Вернуть результат создания элемента с заданным document, localName, namespace, prefix, is и с установленным флагом синхронных настраиваемых элементов (synchronous custom elements).

 

Метод createElementNS(namespace, qualifiedName, options) при вызове должен возвращать результат выполнения внутренних шагов createElementNS с учетом этого this, пространства имен namespace, квалифицированного имени qualifiedName и параметров options.

Примечание!

Параметры parameter createElement() и createElementNS() может быть строкой для веб-совместимости.

Метод createDocumentFragment() при вызове должен возвращать новый узел DocumentFragment с его документом узла, установленным на this.

Метод createTextNode(data) при вызове должен возвращать новый узел Text с его набором данных для data и документом узла, установленным для этого this.

Примечание!

Не выполняется проверка того, что данные data состоят из символов, соответствующих продукту Char.

Метод createCDATASection(data) при вызове должен выполнить следующие шаги:

1. Если этот this является HTML-документом, выбросить исключение DOMException "NotSupportedError".
2. Если данные data содержат строку "]]>", выбросить исключение DOMException "InvalidCharacterError".
3. Вернуть новый узел CDATASection с его набором данных в data и документ узла, установленный для этого this.

Метод createComment(data) при вызове должен возвращать новый узел Comment с его набором данных для данных в data и документ узла, установленный для этого this..

Примечание!

Не выполняется проверка того, состоят ли данные data из символов, соответствующих продукту Char, или содержат ли они два смежных дефиса или заканчиваются дефисом.

При вызове метода createProcessingInstruction(target, data) необходимо выполнить следующие шаги:

1. Если цель target не совпадает с производством Name, то генерирует исключение DOMException «InvalidCharacterError».
2. Если данные data содержат строку «?>», то генерировать исключение DOMException «InvalidCharacterError».
3. Верните новый узел ProcessingInstruction с целью, установленной на target, набором данных для data и документом узла, установленным на this.

Примечание!

Не выполняется проверка того, содержит ли цель target «xml» или «:», или что данные содержат символы, соответствующие продукту Char.

 

Для веб-разработчиков (не нормативно)

clone = document . importNode(node [, deep = false])

Возвращает копию узла node. Если deeptrue, копия также включает потомков узла node.

Если узел node является документом или теневым корнем, выдает исключение DOMException «NotSupportedError«.

node = document . adoptNode(node)

Перемещает узел node из другого документа и возвращает его.

Если узел node является документом, генерирует исключение DOMException «NotSupportedError» или, если узел node является теневым корнем, генерирует исключение DOMException «HierarchyRequestError».

 

При вызове метода importNode(node, deep) необходимо выполнить следующие шаги:

1. Если узел node является документом или теневым корнем, выбросить исключение DOMException "NotSupportedError".
2. Вернуть клон узла node с this и установленным флагом clone children flag, если deep равен true.

Спецификации могут определять «шаги внедрения» (adopting steps) для всех или некоторых узлов. Алгоритм передается node и oldDocument, как указано в  алгоритме внедрения.

Чтобы «внедрить» (adopt) узел node в документ document, выполните следующие действия:

1. Пусть oldDocument будет документом узла node.
2. Если родитель узла node не равен null, удалите узел node.
3. Если document не oldDocument, то:
   1. Для каждого инклюзивного потомка inclusiveDescendant в инклюзивных потомков включающих тень узла node:
      1. Установите документ узла inclusiveDescendant на document.
      2. Если inclusiveDescendant является элементом, то установите документ узла каждого атрибута в списке атрибутов inclusiveDescendant на document.
   2. Для каждого объекта inclusiveDescendant в инклюзивных потомках включающих тень узла node, который является настраиваемым, поставьте в очередь реакцию обратного вызова настраиваемого элемента с помощью inclusiveDescendant, имени обратного вызова «adoptedCallback» и списка аргументов, содержащих oldDocument и document.
   3. Для каждого inclusiveDescendant в инклюзивных потомках включающих тень узла node в древовидном порядке, включающем тень, выполните шаги внедрения с inclusiveDescendant и oldDocument.

 

При вызове метода adoptNode(node) необходимо выполнить следующие шаги:

1. Если узел node является документом, выбросить исключение DOMException "NotSupportedError".
2. Если узел node является теневым корнем, выбросить исключение DOMException «HierarchyRequestError».
3. Если node является узлом DocumentFragment, хост которого не равен null, верните.
4. Внедрите узел node в этот this.
5. Вернуть узел node.

 

Метод createAttribute(localName) при вызове должен выполнить следующие шаги:

1. Если localName не совпадает с производством Name в XML, выбросить исключение DOMException «InvalidCharacterError».
2. Если этот this является документом HTML, установите для localName значение localName в нижнем регистре ASCII.
3. Вернуть новый атрибут, локальное имя которого - localName, а документ узла - this.

 

При вызове метода createAttributeNS(namespace, qualifiedName) необходимо выполнить следующие действия:

1. Пусть namespace, prefix и localName будут результатом передачи пространства имен namespace и квалифицированного имени qualifiedName для проверки и извлечения.

2. Возвращает новый атрибут, пространство имен которого — namespace, префикс пространства именprefix, локальное имяlocalName, а документ узла — этот this.

 

Метод createEvent(interface) при вызове должен выполнить следующие шаги:

1. Пусть конструктор constructor будет null.
2. Если interface является соответствием ASCII без учета регистра для любой из строк в первом столбце в следующей таблице, тогда установите constructor для интерфейса во втором столбце в той же строке, что и соответствующая строка:
String (Строка) Interface (Интерфейс) Notes (Заметки)
«beforeunloadevent» BeforeUnloadEvent [HTML]
«compositionevent» CompositionEvent [UIEVENTS]
«customevent» CustomEvent
«devicemotionevent» DeviceMotionEvent [DEVICE-ORIENTATION]
«deviceorientationevent» DeviceOrientationEvent [DEVICE-ORIENTATION]
«dragevent» DragEvent [HTML]
«event» Event
«events» Event
«focusevent» FocusEvent [UIEVENTS]
«hashchangeevent» HashChangeEvent [HTML]
«htmlevents» Event
«keyboardevent» KeyboardEvent [UIEVENTS]
«messageevent» MessageEvent [HTML]
«mouseevent» MouseEvent [UIEVENTS]
«mouseevents» MouseEvent [UIEVENTS]
«storageevent» StorageEvent [HTML]
«svgevents» Event
«textevent» CompositionEvent [UIEVENTS]
«touchevent» TouchEvent [TOUCH-EVENTS]
«uievent» UIEvent [UIEVENTS]
«uievents» UIEvent [UIEVENTS]
3. Если constructor имеет значение NULL, выбросить исключение DOMException "NotSupportedError".
4. Если интерфейс, указанный конструктором constructor, не отображается в соответствующем глобальном объекте этого this, то генерирует исключение DOMException "NotSupportedError".

Примечание!

Обычно пользовательские агенты отключают поддержку сенсорных событий в некоторых конфигурациях, и в этом случае это предложение будет активировано для интерфейса TouchEvent.

5. Пусть событие event будет результатом создания события при помощи конструктора constructor.
6. Инициализировать атрибут type события event пустой строкой.
7. Инициализируйте атрибут timeStamp события event как DOMHighResTimeStamp, представляющий время с высоким разрешением от начала отсчета времени до настоящего момента.
8. Установите для атрибута isTrusted события event значение false.
9. Флаг инициализации события event не установлен.
10. Вернуть event

Примечание!

Вместо этого следует использовать конструкторы событий.

 

Метод createRange() при вызове должен возвращать новый активный диапазон с (this, 0) в качестве начала и конца.

Примечание!

Вместо этого можно использовать конструктор Range().

 

При вызове метода createNodeIterator(root, whatToShow, filter) необходимо выполнить следующие шаги:

1. Пусть итератор iterator будет новым объектом NodeIterator.
2. Установите корень итератора iterator и ссылку итератора iterator на root.
3. Установите указатель перед ссылкой итератора iterator на true.
4. Установите для итератора iterator whatToShow значение whatToShow.
5. Установите фильтр итератора iterator на filter.
6. Верните iterator

 

При вызове метода createTreeWalker(root, whatToShow, filter) необходимо выполнить следующие шаги:

1. Пусть пешеход walker будет новым объектом TreeWalker.
2. Установите корень walker и ток walker на root.
3. Установите для walker whatToShow значение whatToShow.
4. Установите фильтр пешехода walker на filter.
5. Верните walker

 

4.5.1 Интерфейс DOMImplementation (Реализация DOM)

Пользовательские агенты должны создавать объект DOMImplementation всякий раз, когда создается документ, и связывать его с этим документом.

IDL

[Exposed=Window]
interface DOMImplementation {
   [NewObject] DocumentType createDocumentType(DOMString qualifiedName, DOMString publicId, DOMString systemId);
   [NewObject] XMLDocument createDocument(DOMString? namespace, [LegacyNullToEmptyString] DOMString qualifiedName, optional DocumentType? doctype = null);
   [NewObject] Document createHTMLDocument(optional DOMString title);

boolean hasFeature(); // бесполезный; всегда возвращает истину
};

 

Для веб-разработчиков (не нормативно)

doctype = document . implementation . createDocumentType(qualifiedName, publicId, systemId)

Возвращает doctype с указанными qualifiedName, publicId и systemId. Если qualifiedName не соответствует продукту Name, генерируется исключение DOMException «InvalidCharacterError», а если оно не соответствует продукту QName, генерируется исключение DOMException «NamespaceError».

doc = document . implementation . createDocument(namespace, qualifiedName [, doctype = null])

Возвращает XMLDocument с элементом документа, локальное имя которого — это qualifiedName, а пространство именnamespace (кроме случаев, когда qualifiedName является пустой строкой), и с doctype, если он указан, в качестве его типа документа.

Этот метод генерирует те же исключения, что и метод createElementNS(), когда вызывается с пространством имен namespace и квалифицированным именем qualifiedName.

doc = document . implementation . createHTMLDocument([title])

Возвращает документ с уже построенным базовым деревом, включая элемент заголовка title, если не указан аргумент заголовка title.

 

При вызове метода createDocumentType(qualifiedName, publicId, systemId) необходимо выполнить следующие действия:

1. Проверяем на соответсвие qualifiedName.
2. Верните новый тип документа с qualifiedName как его именем, publicId в качестве общедоступного идентификатора и systemId в качестве идентификатора системы, а для документа узла установите соответствующий документ этого this.

Примечание!

Не выполняется проверка того, что кодовые точки publicId соответствуют продукту PubidChar или что systemId не содержит одновременно ‘"‘ и «'«.

 

Метод createDocument(namespace, qualifiedName, doctype) при вызове должен выполнять следующие действия:

1. Пусть document будет новым объектом XMLDocument.
2. Пусть element будет null.
3. Если qualifiedName не является пустой строкой, тогда установите для element результат выполнения внутренних шагов createElementNS, данного document, namespace, qualifiedName и пустого словаря.
4. Если doctype не равно null, добавьте doctype к document.
5. Если element не равен null, добавьте element в document.
6. Источник document - это источник связанного документа этого this.
7. Тип содержимого document определяется пространством имен namespace:
   HTML namespace
      application/xhtml+xml
   SVG namespace
      image/svg+xml
   Любое другое пространство имен
      application/xml
8. Вернуть document

 

При вызове метода createHTMLDocument(title) необходимо выполнить следующие действия:

1. Пусть doc будет новым документом, который является документом HTML.
2. Установите тип содержимого документа doc на «text/html».
3. Добавьте новый тип документа с именем «html» и с документом узла, установленным на doc, в doc.
4. Добавьте в doc результат создания элемента, заданного doc, html и пространством имен HTML в doc.
5. Добавьте результат создания элемента, заданного doc, head и пространством имен HTML, к элементу html, созданному ранее.
6. Если указан заголовок title:
   1. Добавьте результат создания элемента с заданным doc, title и пространством имен HTML к ранее созданному элементу head.
   2. Добавьте новый узел Text с его набором данных в title (который может быть пустой строкой) и его документом узла, установленным в doc, к элементу title, созданному ранее.
7. Добавьте результат создания элемента, заданного документом doc, body и пространством имен HTML, к элементу html, созданному ранее.
8. Источник документа doc - это источник связанного документа этого this.
9. Вернуть doc

 

При вызове метода hasFeature() он должен возвращать значение true.

Примечание!

Изначально hasFeature() сообщал, заявлял ли пользовательский агент о поддержке данной функции DOM, но опыт показал, что это было не так надежно или детально, как простая проверка наличия требуемых объектов, атрибутов или методов. Таким образом, он больше не будет использоваться, но продолжает существовать (и просто возвращает true), чтобы старые страницы не перестали работать.

 

4.6 Интерфейс DocumentType (Тип документа)

IDL

[Exposed=Window]
interface DocumentType : Node {
   readonly attribute DOMString name;
   readonly attribute DOMString publicId;
   readonly attribute DOMString systemId;
};

Узлы DocumentType просто известны как «типы документа» (doctypes).

Типы документа имеют связанное «имя» (name), «публичный идентификатор» (public ID) и «системный идентификатор» (system ID).

Когда создается тип документа, всегда дается его имя. Если это не указано явно при создании типа документа, его общедоступный идентификатор и системный идентификатор являются пустой строкой.

Получатель атрибута name должен возвращать имя этого this.

Получатель атрибута publicId должен возвращать общедоступный идентификатор этого this.

Получатель атрибута systemId должен возвращать системный идентификатор этого this.

 

4.7 Интерфейс DocumentFragment (Фрагмент документа)

IDL

[Exposed=Window]
interface DocumentFragment : Node {
   constructor();
};

Узел DocumentFragment имеет связанный «хост» (host) (null или элемент в другом дереве узлов). Это значение равно null, если не указано иное.

Объект A является «инклюзивным предком включающим хост» (host-including inclusive ancestor) объекта B, если либо A является инклюзивным предком B, либо если корень B имеет не-null хост, а A является инклюзивным предком включающим хост хоста корня B.

Примечание!

Концепция хоста узла DocumentFragment полезна для элемента template HTML и для теневых корней и влияет на алгоритмы предварительной вставки и замены.

 

Для веб-разработчиков (не нормативно)

tree = new DocumentFragment()

Возвращает новый узел DocumentFragment.

Конструктор DocumentFragment() при вызове должен возвращать новый узел DocumentFragment, документ узла которого является связанным Document текущего глобального объекта.

 

4.8 Интерфейс ShadowRoot (Теневой корень)

IDL

[Exposed=Window]
interface ShadowRoot : DocumentFragment {
   readonly attribute ShadowRootMode mode;
   readonly attribute Element host;
   attribute EventHandler onslotchange;
};

enum ShadowRootMode { "open", "closed" };

Узлы ShadowRoot просто известны как «теневые корни» (shadow roots).

У теневых корней есть связанный «режим» (mode) («open» or «closed» — «открытый» или «закрытый»).

У теневых корней есть связанный «фокус делегатов» (delegates focus). Изначально установлено значение false.

У теневых корней есть связанный «доступ к внутренним элементам» (available to element internals). Изначально установлено значение false.

У теневых корней есть связанный хост, который никогда не бывает null.

Алгоритм получения родителя теневого корня при заданном событии event возвращает null, если флаг составленного события event не установлен, а теневой корень является корнем цели вызова первой структуры пути к событию event, а в противном случае — хостом теневого корня.

Получатель атрибута mode должен возвращать режим этого this.

Получатель атрибута host должен возвращать хост этого this.

Атрибут onslotchange — это IDL-атрибут обработчика событий для обработчика событий onslotchange, тип события обработчика которого — slotchange.

 

В «древовидном порядке с включением теней» (shadow-including tree order) — это предварительный порядок с включением теней, обхода в глубину дерева узлов.

«Предварительный порядок с включением теней, обхода в глубину» (Shadow-including preorder, depth-first traversal) дерева узлов tree  — это предварительный порядок, обхода tree в глубину, причем для каждого теневого хоста, встречающегося в tree, предварительный порядок с учетом тени, обхода в глубину дерева узлов теневого корня этого элемента просто после того, как он встречается.

«Включающий тень корень» (shadow-including root) объекта — это его включающий тень корень, хоста корня, если корень объекта является теневым корнем, и его корень в противном случае.

Объект A является «потомком с тенью» (shadow-including descendant) объекта B, если A является потомком B, или корень A является теневым корнем, а хост корня A является инклюзивным потомком включающим тень B.

«Инклюзивный потомок с тенью» (shadow-including inclusive descendant) — это объект или один из его потомков с тенью.

Объект A является «предком с тенью» (shadow-including ancestor) объекта B, если и только если B является теневым потомком A.

«Инклюзивный предок с тенью» (shadow-including inclusive ancestor) — это объект или один из его включающих тень предков.

Узел A является «закрытым-теневым-скрытым» (closed-shadow-hidden) от узла B, если выполняются все следующие условия:

Чтобы «перенацелить» (retarget) объект A на объект B, повторяйте эти шаги, пока они не вернут объект:

1. Если верно одно из следующих утверждений
   А не узел
   Корень A - это не теневой корень
   B - узел, а корень A - инклюзивный теневой предок B
затем верните A.
2. Установите A в качестве хоста корня A.

Примечание!

Алгоритм перенацеливания используется при отправке событий, а также в других спецификациях, таких как полноэкранный режим.[FULLSCREEN]

 

4.9 Интерфейс Element (Элемент)

IDL

[Exposed=Window]
interface Element : Node {
   readonly attribute DOMString? namespaceURI;
   readonly attribute DOMString? prefix;
   readonly attribute DOMString localName;
   readonly attribute DOMString tagName;

   [CEReactions] attribute DOMString id;
   [CEReactions] attribute DOMString className;
   [SameObject, PutForwards=value] readonly attribute DOMTokenList classList;
   [CEReactions, Unscopable] attribute DOMString slot;

   boolean hasAttributes();
   [SameObject] readonly attribute NamedNodeMap attributes;
   sequence<DOMString> getAttributeNames();
   DOMString? getAttribute(DOMString qualifiedName);
   DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
   [CEReactions] undefined setAttribute(DOMString qualifiedName, DOMString value);
   [CEReactions] undefined setAttributeNS(DOMString? namespace, DOMString qualifiedName, DOMString value);
   [CEReactions] undefined removeAttribute(DOMString qualifiedName);
   [CEReactions] undefined removeAttributeNS(DOMString? namespace, DOMString localName);
   [CEReactions] boolean toggleAttribute(DOMString qualifiedName, optional boolean force);
   boolean hasAttribute(DOMString qualifiedName);
   boolean hasAttributeNS(DOMString? namespace, DOMString localName);

   Attr? getAttributeNode(DOMString qualifiedName);
   Attr? getAttributeNodeNS(DOMString? namespace, DOMString localName);
   [CEReactions] Attr? setAttributeNode(Attr attr);
   [CEReactions] Attr? setAttributeNodeNS(Attr attr);
   [CEReactions] Attr removeAttributeNode(Attr attr);

   ShadowRoot attachShadow(ShadowRootInit init);
   readonly attribute ShadowRoot? shadowRoot;

   Element? closest(DOMString selectors);
   boolean matches(DOMString selectors);
   boolean webkitMatchesSelector(DOMString selectors); // исторический псевдоним .matches

   HTMLCollection getElementsByTagName(DOMString qualifiedName);
   HTMLCollection getElementsByTagNameNS(DOMString? namespace, DOMString localName);
   HTMLCollection getElementsByClassName(DOMString classNames);

   [CEReactions] Element? insertAdjacentElement(DOMString where, Element element); // исторический
   undefined insertAdjacentText(DOMString where, DOMString data); // исторический
};

dictionary ShadowRootInit {
   required ShadowRootMode mode;
   boolean delegatesFocus = false;
};

Узлы Element называются просто «элементами» (elements).

Элементы имеют связанное «пространство имен» (namespace), «префикс пространства имен» (namespace prefix), «локальное имя» (local name), «состояние настраиваемого элемента» (custom element state), «определение настраиваемого элемента» (custom element definition),  «is значение» (value). Когда элемент создаётся, все эти значения инициализируются.

Состояние настраиваемого элемента элемента может быть одним из следующих: «undefined«, «failed«, «uncustomized«, «precustomized«, or «custom» («Не определено», «Не выполнено», «Не настроено», «Предварительно настроено» или «Пользовательское»). Элемент, чье состояние настраиваемого элемента является «uncustomized» или «custom«, называется «определённым» (defined). Элемент, чье состояние настраиваемого элемента является «custom«, называется «настраиваемым» (custom).

Примечание!

Независимо от того, определен ли элемент, используется для определения поведения псевдокласса :defined. Независимо от того, является ли элемент настраиваемым, используется для определения поведения алгоритмов мутации. Состояния «failed» и «precustomized» используются для того, чтобы гарантировать, что если конструктор настраиваемого элемента не будет правильно выполняться в первый раз, он не будет выполнен снова при обновлении.

 

Пример

Следующий код иллюстрирует элементы в каждом из этих четырех состояний:

<!DOCTYPE html>
<script>
   window.customElements.define("sw-rey", class extends HTMLElement {})
   window.customElements.define("sw-finn", class extends HTMLElement {}, { extends: "p" })
   window.customElements.define("sw-kylo", class extends HTMLElement {
      constructor() {
         // super() намеренно опущено в этом примере
      }
   })
</script>

<!-- "undefined" (not defined, not custom) -->
<sw-han></sw-han>
<p is="sw-luke"></p>
<p is="asdf"></p>

<!-- "failed" (not defined, not custom) -->
<sw-kylo></sw-kylo>

<!-- "uncustomized" (defined, not custom) -->
<p></p>
<asdf></asdf>

<!-- "custom" (defined, custom) -->
<sw-rey></sw-rey>
<p is="sw-finn"></p>

 

Элементы также имеют связанный «теневой корень» (shadow root) (null или теневой корень). Это значение равно null, если не указано иное. Элемент является «теневым хостом» (shadow host), если его теневой корень не равен null.

«Полное имя» (qualified name) элемента — это его локальное имя, если его префикс пространства имен равен null, и его префикс пространства имен, за которым следует двоеточие «:», за которым следует его локальное имя, в противном случае.

«Полное имя в верхнем регистре в формате HTML» (HTML-uppercased qualified name) элемента является возвращаемым значением следующих шагов:

1. Пусть qualifiedName будет полным именем этого this.
2. Если этот this находится в пространстве имен HTML, а его узловой документ является HTML-документом, тогда установите для qualifiedName значение qualifiedName в верхнем регистре ASCII.
3. Верните qualifiedName

Примечание!

Пользовательские агенты могут оптимизировать полное имя и полное имя в верхнем регистре HTML, сохраняя их во внутренних слотах.

 

Чтобы «создать элемент» (create an element), учитывая document, localName, namespace и необязательный prefix, is и флаг синхронных настраиваемых элементов (synchronous custom elements flag), выполните следующие действия:

1. Если prefix не был указан, пусть prefix будет null.
2. Если is не задано, пусть is будет null.
3. Пусть результат result будет нулевым.
4. Пусть определение definition будет результатом поиска определения настраиваемого элемента с учетом документа document, пространства имен namespace, локального имени localName и is.
5. Если definition не равно null и имя definition не совпадает с его локальным именем (т. е. definition представляет собой настраиваемый встроенный элемент), тогда:
   1. Пусть interface будет интерфейсом элемента для localName и пространства имен HTML.
   2. Установить результат result для нового элемента, который реализует interface, без атрибутов, пространство имен установлено на пространство имен HTML, префикс пространства имен установлен на prefix, локальное имя установлено на localName, состояние настраиваемого элемента установлено на "undefined", определение настраиваемого элемента установлено на null, значение is установлено на is, а для документа узла установлено значение document.
   3. Если установлен флаг синхронных настраиваемых элементов (synchronous custom elements flag), запустите этот шаг, перехватывая любые исключения:
         1. Обновите элемент element, используя определение definition.
      Если этот шаг вызвал исключение, то:
         1. Сообщите об исключении.
         2. Установите состояние настраиваемого элемента result как "failed" ("сбой").
   4. В противном случае поставьте в очередь реакцию обновления настраиваемого элемента с учетом результата result и определения definition.
6. В противном случае, если definition не равно null, тогда:
   1. Если установлен флаг синхронных настраиваемых элементов (synchronous custom elements flag), выполните следующие действия, перехватив любые исключения:
      1. Пусть C будет конструктором definition.
      2. Установите result равным результату построения C без аргументов.
      3. Утверждение: инициализируются состояние настраиваемого элемента result и определение настраиваемого элемента.
      4. Утверждение: пространство имен результата result - это пространство имен HTML.

Примечание!

IDL обеспечивает, что результатом является объект HTMLElement, который использует пространство имен HTML.

      5. Если список атрибутов result не пуст, то бросить исключение DOMException "NotSupportedError".
      6. Если у result есть дети, выбросить исключение DOMException "NotSupportedError".
      7. Если родитель result не равен null, выбросить исключение DOMException "NotSupportedError".
      8. Если документ узла result не является document, выбросить исключение DOMException "NotSupportedError".
      9. Если локальное имя результата не равно localName, выбросить исключение DOMException "NotSupportedError".
      10. Установите префикс пространства имен result на prefix.
      11. Установите для is значения result значение null.
   Если какой-либо из этих шагов вызвал исключение, то:
      1. Сообщите об исключении.
      2. Установить result для нового элемента, который реализует интерфейс HTMLUnknownElement, без атрибутов, пространство имен установлено на пространство имен HTML, префикс пространства имен установлен на prefix, локальное имя установлено на localName, состояние настраиваемого элемента установлено на "failed" ("сбой"), определение настраиваемого элемента установлено на null , is значение имеет значение null, а документ узла имеет значение document.
   2. Иначе:
      1. Установить result для нового элемента, который реализует интерфейс HTMLElement, без атрибутов, пространство имен установлено на пространство имен HTML, префикс пространства имен установлен на prefix, локальное имя установлено на localName, состояние настраиваемого элемента установлено на "undefined", определение настраиваемого элемента установлено на null , is значение имеет значение null, а документ узла имеет значение document.
      2. Поставить в очередь реакцию обновления настраиваемого элемента с учетом результата result и определения definition.
7. Иначе
   1. Пусть interface будет интерфейсом элемента для localName и namespace.
   2. Установить result для нового элемента, который реализует interface, без атрибутов, пространство имен установлено на namespace, префикс пространства имен установлен на prefix, локальное имя установлено на localName, состояние настраиваемого элемента установлено на "uncustomized"», определение настраиваемого элемента установлено на null, is значение имеет значение is, а документ узла имеет значение document.
   3. Если namespace является пространством имен HTML и либо localName является допустимым именем настраиваемого элемента, либо is имеет значение, отличное от NULL, установите для состояния настраиваемого элемента result значение "undefined".
8. Вернуть result

 

У элементов также есть «список атрибутов» (attribute list), который представляет собой список, представленный через NamedNodeMap. Если элемент не указан явно, его список атрибутов пуст.

Элемент «имеет» (has) атрибут A, если его список атрибутов содержит A.

Эта и другие спецификации могут определять «шаги изменения атрибутов» (attribute change steps) для элементов. Алгоритму передаются element, localName, oldValue, value и namespace.

Чтобы «обработать изменения атрибутов» (handle attribute changes) для атрибута attribute с element, oldValue и newValue, выполните следующие действия:

1. Поставить в очередь запись мутации "attributes" для element с локальным именем attribute, пространством имен attribute, oldValue, «», «», null и null.
2. Если element является настраиваемым, то поставьте в очередь реакцию обратного вызова настраиваемого элемента с element, именем обратного вызова "attributeChangedCallback" и списком аргументов, содержащим локальное имя attribute, oldValue, newValue и пространство имен attribute.
3. Выполните шаги по изменению атрибута с element, локальным именем attribute, oldValue, newValue и пространством имен attribute.

 

Чтобы «изменить» (change) атрибут attribute на value, выполните следующие действия:

1. Обработайте изменение атрибута для attribute с помощью элемента attribute, значения attribute и value.
2. Установите для значения attribute  - value.

 

Чтобы «добавить» (append) атрибут attribute к элементу element, выполните следующие действия:

1. Обрабатывать изменения атрибута для attribute с element, null и значения attribute.
2. Добавить attribute в список атрибутов element.
3. Установите элемент attribute на element.

 

Чтобы «удалить» (remove) атрибут attribute, выполните следующие действия:

1. Обработайте изменения атрибута для attribute с помощью элемента attribute, значения attribute и null.
2. Удалите attribute из списка атрибутов элемента attribute.
3. Установите для элемента attribute значение null.

 

Чтобы «заменить» (replace) атрибут oldAttr на атрибут newAttr, выполните следующие действия:

1. Обработайте изменения атрибута oldAttr с помощью элемента oldAttr, значения oldAttr и значения newAttr.
2. Замените oldAttr на newAttr в списке атрибутов элемента oldAttr.
3. Установите элемент newAttr на элемент oldAttr.
4. Установите для элемента oldAttr значение null.

 

Чтобы «получить атрибут по имени» (get an attribute by name) с учетом qualifiedName и элемента element, выполните следующие действия:

1. Если element находится в пространстве имен HTML, а его узловой документ является HTML-документом, тогда установите для qualifiedName значение qualifiedName в нижнем регистре ASCII.
2. Вернуть первый атрибут в списке атрибутов элемента element, полное имя которого - qualifiedName, в противном случае - null.

Чтобы «получить атрибут по пространству имен и локальному имени» (get an attribute by namespace and local name) с учетом namespace, localName и элемента element, выполните следующие действия:

1. Если namespace является пустой строкой, установите для нее значение null.
2. Вернуть атрибут в списке атрибутов element, пространство имен которого - namespace, а локальное имя - localName, если есть, и null в противном случае.

Чтобы «получить значение атрибута» (get an attribute value) с учетом элемента element, localName и, возможно, namespace (null, если не указано иное), выполните следующие действия:

1. Пусть attr будет результатом получения атрибута из заданного namespace, localName и element.
2. Если attr имеет значение null, вернуть пустую строку.
3. Вернуть значение attr.

Чтобы «установить атрибут» (set an attribute) с учетом attr и element, выполните следующие действия:

1. Если элемент attr не является ни null, ни element, генерировать исключение DOMException "InUseAttributeError".
2. Пусть oldAttr будет результатом получения атрибута, заданного пространством имен attr, локальным именем attr и element.
3. Если oldAttr - это attr, верните attr.
4. Если oldAttr не равен null, замените oldAttr на attr.
5. В противном случае добавьте attr к элементу element.
6. Верните oldAttr.

Чтобы «установить значение атрибута» (set an attribute value) для элемента element, используя localName и значение value, а также необязательный префикс prefix и пространство имен namespace, выполните следующие действия:

1. Если префикс prefix не указан, установите для него значение null.
2. Если пространство имен namespace не указано, установите для него значение null.
3. Пусть attribute будет результатом получения атрибута с заданным namespace, localName и element.
4. Если attribute имеет значение null, создайте атрибут, пространство имен которого - namespace, префикс пространства имен - prefix, локальное имя - localName, значение - value, а документ узла - документ узла element, затем добавьте этот атрибут к элементу element и затем верните его.
5. Измените attribute на value.

Чтобы «удалить атрибут по имени» (remove an attribute by name), заданному qualifiedName и элементом element, выполните следующие действия:

1. Пусть attr будет результатом получения атрибута с заданным именем qualifiedName и element.
2. Если attr не равно null, удалите attr.
3. Вернуть attr.

Чтобы «удалить атрибут по пространству имен и локальному имени» (remove an attribute by namespace and local name) с учетом namespace, localName и элемента element, выполните следующие действия:

1. Пусть attr будет результатом получения атрибута из заданного namespace, localName и element.
2. Если attr не равно null, удалите attr.
3. Вернуть attr.

 

Элемент может иметь связанный «уникальный идентификатор» (unique identifier — ID)

Примечание!

Исторически элементы могли иметь несколько идентификаторов, например, с помощью атрибута id HTML  и DTD. Эта спецификация делает идентификаторы ID концепцией DOM и позволяет использовать только один элемент для каждого элемента, задаваемый атрибутом id.

Чтобы обновить идентификатор элемента, выполните следующие шаги по изменению атрибута:

1. Если localName имеет значение id, namespace равно NULL, а value равно NULL или пустая строка, идентификатор element не устанавливается.
2. В противном случае, если localName имеет значение id, namespace равно null, тогда установите для идентификатора element значение value.

Примечание!

Хотя эта спецификация определяет требования к атрибутам class, id и slot для любого элемента, она не делает никаких заявлений относительно того, соответствует ли их использование требованиям или нет.

 

Родитель узла типа Element известен как «родительский элемент» (parent element). Если у узла есть родитель другого типа, его родительский элемент имеет значение NULL.

 

Для веб-разработчиков (не нормативно)

namespace = element . namespaceURI

Возвращает пространство имен.

prefix = element . prefix

Возвращает префикс пространства имен.

localName = element . localName

Возвращает локальное имя.

qualifiedName = element . tagName

Возвращает полное имя в верхнем регистре HTML.

 

Получатель атрибута namespaceURI должен возвращать пространство имен этого this.

Получатель атрибута prefix должен возвращать префикс пространства имен этого this.

Получатель атрибута localName должен возвращать локальное имя этого this.

Получатель атрибута tagName должен возвращать полное имя HTML в верхнем регистре этого this.

 

Для веб-разработчиков (не нормативно)

element . id [ = value ]

Возвращает значение содержимого атрибута «id», элемента element. Можно настроить, чтобы изменить это.

element . className [ = value ]

Возвращает значение содержимого атрибута «class«, элемента element. Можно настроить, чтобы изменить это.

element . classList

Позволяет управлять содержимым атрибута «class«, элемента element как набором токенов, разделенных пробелами, через объект DOMTokenList.

element . slot [ = value ]

Возвращает значение содержимого атрибута «slot«, элемента element. Можно настроить, чтобы изменить это.

Атрибуты IDL, которые определены для «отражения» (reflect) содержимого атрибута с заданным именем name, должны иметь средства получения и установки, которые выполняют следующие шаги:

Получатель (getter)

Вернуть результат выполнения получения значение атрибута с учетом этого this и имени name.

Установщик (setter)

Установите значение атрибута для этого this, используя имя name и заданное значение.

Атрибут id должен отражать содержимое атрибута  «id«.

Атрибут className должен отражать содержимое атрибута «class«.

Получатель атрибута classList должен возвращать объект DOMTokenList, чьим связанным элементом является this, а локальное имя связанного атрибута — «class«. Набор токенов этого конкретного объекта DOMTokenList также известен как «классы» (classes) элемента.

Атрибут slot должен отражать содержимое атрибута «slot«.

Примечание!

id, class и slot по сути являются суперглобальными атрибутами, поскольку они могут появляться в любом элементе, независимо от пространства имен этого элемента.

 

Для веб-разработчиков (не нормативно)

element . hasAttributes()

Возвращает true, если элемент element имеет атрибуты, и false в противном случае.

element . getAttributeNames()

Возвращает полные имена всех атрибутов элемента element. Может содержать дубликаты.

element . getAttribute(qualifiedName)

Возвращает первый атрибут элемента element, чьё полное имяqualifiedName, и null, если такого атрибута нет, в противном случае.

element . getAttributeNS(namespace, localName)

Возвращает атрибут элемента element, чьё пространство именnamespace, а локальное имяlocalName, а в противном случае — null, если такого атрибута нет.

element . setAttribute(qualifiedName, value)

Устанавливает значение для первого атрибута элемента element, чьё полное имя является qualifiedName, равное value.

element . setAttributeNS(namespace, localName, value)

Устанавливает значение атрибута элемента element, пространство имен которого — namespace, а локальное имяlocalName, равное value.

element . removeAttribute(qualifiedName)

Удаляет первый атрибут элемента element, полное имя которого — qualifiedName.

element . removeAttributeNS(namespace, localName)

Удаляет атрибут элемента element, пространство имен которого — namespace, а локальное имяlocalName.

element . toggleAttribute(qualifiedName [, force])

Если force не задано, «переключает» qualifiedName, удаляя его, если оно присутствует, и добавляя, если оно отсутствует. Если force истинна (true), добавляет qualifiedName. Если force имеет значение false, удаляет qualifiedName.

Возвращает истину (true), если теперь присутствует qualifiedName, и ложь в противном случае.

element . hasAttribute(qualifiedName)

Возвращает истину (true), если элемент element имеет атрибут, чьё полное имя является qualifiedName, и ложь (false) в противном случае.

element . hasAttributeNS(namespace, localName)

Возвращает истину (true), если элемент element имеет атрибут, чьё пространство именnamespace, а локальное имяlocalName.

 

Метод hasAttributes() при вызове должен возвращать false, если этот список атрибутов пуст, и true в противном случае.

Получатель атрибута attributes должен возвращать связанный NamedNodeMap.

Метод getAttributeNames() при вызове должен возвращать полные имена атрибутов в списке атрибутов этого this по порядку, а в противном случае — новый список.

Примечание!

Их уникальность не гарантируется.

При вызове метода getAttribute(qualifiedName) необходимо выполнить следующие действия:

1. Пусть attr будет результатом получения атрибута с qualifiedName и this.
2. Если attr имеет значение null, вернуть null.
3. Вернуть значение attr.

При вызове метода getAttributeNS(namespace, localName) необходимо выполнить следующие действия:

1. Пусть attr будет результатом получения атрибута с заданным namespace, localName и this.
2. Если attr имеет значение null, вернуть null.
3. Вернуть значение attr.

Метод setAttribute(qualifiedName, value) при вызове должен выполнить следующие шаги:

1. Если qualifiedName не совпадает с производством Name в XML, генерируется исключение DOMException «InvalidCharacterError».
2. Если this находится в пространстве имен HTML, а его документ узла является HTML-документом, тогда установите для qualifiedName значение qualifiedName в нижнем регистре ASCII.
3. Пусть attribute будет первым атрибутом в списке атрибутов этого this, чьё полное имя будет qualifiedName, в противном случае - null.
4. Если attribute имеет значение NULL, создайте атрибут, локальное имя которого - qualifiedName, значение - value, а документ узла - документ узла этого this, затем добавьте этот атрибут к this и затем вернитесь.
5. Измените attribute на value.

При вызове метода setAttributeNS(namespace, qualifiedName, value) необходимо выполнить следующие шаги:

1. Пусть namespace, prefix и localName будут результатом передачи namespace и qualifiedName для проверки и извлечения.
2. Установите значение атрибута для этого this, используя localName, value, а также prefix и namespace.

Метод removeAttribute(qualifiedName) при вызове должен удалить атрибут с qualifiedName и this, а затем вернуть значение undefined.

Метод removeAttributeNS(namespace, localName) при вызове должен удалить атрибут, заданный namespace, localName и this, а затем вернуть значение undefined.

При вызове метода hasAttribute(qualifiedName) необходимо выполнить следующие действия:

1. Если this находится в пространстве имен HTML, а его документ узла является HTML-документом, тогда установите для qualifiedName значение qualifiedName в нижнем регистре ASCII.
2. Верните истину (true), если у этого this имеется атрибут, чьё полное имя - qualifiedName, и ложь (false) в противном случае.

При вызове метода toggleAttribute(qualifiedName, force) необходимо выполнить следующие действия:

1. Если qualifiedName не совпадает с производством Name в XML, генерируется исключение DOMException «InvalidCharacterError».
2. Если this находится в пространстве имен HTML, а его документ узла является HTML-документом, тогда установите для qualifiedName значение qualifiedName в нижнем регистре ASCII.
3. Пусть attribute будет первым атрибутом в списке атрибутов этого this, чьё полное имя будет qualifiedName, в противном случае - null.
4. Если attribute равен null, то:
   1. Если force не задан или имеет значение true, создайте атрибут, локальное имя которого - qualifiedName, значение - это пустая строка, а документ узла - это документ узла этого this, затем добавьте этот атрибут к this и верните true.
   2. Вернуть false.
5. В противном случае, если force не задано или имеет значение false, удалите атрибут, заданный qualifiedName и this, а затем верните false.
6. Верните истину - true.

При вызове метода hasAttributeNS(namespace, localName) необходимо выполнить следующие действия:

1. Если namespace является пустой строкой, установите для нее значение null.
2. Верните true, если this имеет атрибут, пространство имен которого - namespace, а локальное имя - localName, и false в противном случае.

 

Метод getAttributeNode(qualifiedName) при вызове должен возвращать результат получения атрибута с заданным qualifiedName и this.

Метод getAttributeNodeNS(namespace, localName) при вызове должен возвращать результат получения атрибута с заданным namespace, localName и this.

Методы setAttributeNode(attr) и setAttributeNodeNS(attr) при вызове должны возвращать результат установки атрибута с данным attr и this.

При вызове метода removeAttributeNode(attr) необходимо выполнить следующие действия:

1. Если список атрибутов этого this не содержит attr, выбросить исключение DOMException "NotFoundError".
2. Удалить attr
3. Вернуть attr

 

Для веб-разработчиков (не нормативно)

var shadow = element . attachShadow(init)

Создает теневой корень для элемента element и возвращает его.

var shadow = element . shadowRoot

Возвращает теневой корень элемента element, если он есть, и если режим теневого корня «open«, и null в противном случае.

 

При вызове метода attachShadow(init) необходимо выполнить следующие действия:

1. Если пространство имен этого this не является пространством имен HTML, выбросить исключение DOMException "NotSupportedError".
2. Если локальное имя этого this не одно из следующих:
      допустимое имя настраиваемого элемента
      "article", "aside", "blockquote", "body", "div", "footer", "h1", "h2", "h3", "h4", "h5", "h6", "header", "main", "nav", "p", "section", "span"
   затем выбросить исключение DOMException "NotSupportedError".
3. Если локальное имя этого this является допустимым именем настраиваемого элемента или is значение этого this не равно null, то:
   1. Пусть definition будет результатом поиска определения настраиваемого элемента по данному документу узла этого this, его пространству имен, его локальному имени и его is значению.
   2. Если definition не равно null, а значение отключенная тень definition является истиной true, то генерируется исключение DOMException "NotSupportedError".
4. Если this является теневым хостом, выбросить исключение DOMException "NotSupportedError".
5. Пусть shadow будет новым теневым корнем, документ узла которого - это документ узла этого this, хост является this, а режим является mode init.
6. Установите фокус делегатов тени shadow на delegatesFocus в init.
7. Если настраиваемое состояние элемента этого this является "precustomized" или "custom", тогда установите для shadow, доступной для внутренних элементов, значение true.
8. Установите теневой корень этого this на shadow.
9. Верните shadow

Получатель атрибута shadowRoot должен выполнить следующие шаги:

1. Пусть тень shadow будет корнем тени этого this.
2. Если тень shadow равна null или ее режим "closed" («закрыт»), то верните null.
3. Верните shadow

 

Для веб-разработчиков (не нормативно)

element . closest(selectors)

Возвращает первого (начиная с элемента element) инклюзивного предка, который соответствует селекторам selectors, в противном случае — null.

element . matches(selectors)

Возвращает true, если сопоставление селекторов selectors с корнем элемента element дает element, и false в противном случае.

 

Метод closest(selectors) при вызове должен выполнить следующие шаги:

1. Пусть s будет результатом синтаксического анализа селектора из selectors. [SELECTORS4]
2. Если s является ошибкой, выбросить исключение DOMException "SyntaxError".
3. Пусть elements будут инклюзивными предками этого this, которые являются элементами в обратном древовидном порядке.
4. Для каждого element в elements, если сопоставляется селектор с элементом, используя s, element и :scope element this возвращает успех, возвращает element. [SELECTORS4]
5. Вернуть null

Методы matches(selectors) и webkitMatchesSelector(selectors) при вызове должны выполнять следующие шаги:

1. Пусть s будет результатом синтаксического анализа селектора из selectors. [SELECTORS4]
2. Если s является ошибкой, выбросить исключение DOMException "SyntaxError".
3. Вернуть true, если результат сопоставления селектора с элементом с использованием s, element и :scope element this возвращает успех, иначе false. [SELECTORS4]

 

Метод getElementsByTagName(qualifiedName) при вызове должен возвращать список элементов с квалифицированным именем qualifiedName для этого this.

Метод getElementsByTagNameNS(namespace, localName) при вызове должен возвращать список элементов с пространством имен namespace и локальным именем localName для этого this.

Метод getElementsByClassName(classNames) при вызове должен возвращать список элементов с именами классов classNames этого this.

 

Чтобы «вставить рядом» (insert adjacent), с элементом element, строкой where и узлом node, выполните шаги, связанные с первым совпадением ASCII без учета регистра для where:

«beforebegin«

Если родитель элемента element равен null, верните null.

Вернуть результат предварительной вставки узла node в родителя элемента element перед элементом element.

«afterbegin«

Вернуть результат предварительной вставки узла node в элемент element перед первым ребёнком элемента element.

«beforeend«

Вернуть результат предварительной вставки узла node в элемент element перед null.

«afterend«

Если родитель элемента element равен null, верните null.

Вернуть результат предварительной вставки узла node в родителя элемента element перед следующим родственником элемента element.

Иначе

Выбросить исключение DOMException «SyntaxError«.

 

Метод insertAdjacentElement(where, element) при вызове должен возвращать результат выполнения вставки рядом, передать this, where и element.

При вызове метода insertAdjacentText(where, data) необходимо выполнить следующие действия:

1. Пусть text будет новым узлом Text, данные которого являются data, а документ узла - документом узла этого this.
2. Выполните вставку рядом, учитывая this, where и text.

 

Примечание!

Этот метод ничего не возвращает, потому что он существовал до того, как мы смогли его спроектировать.

 

4.9.1 Интерфейс NamedNodeMap (Карта именованных узлов)

IDL

[Exposed=Window,
LegacyUnenumerableNamedProperties]
interface NamedNodeMap {
   readonly attribute unsigned long length;
   getter Attr? item(unsigned long index);
   getter Attr? getNamedItem(DOMString qualifiedName);
   Attr? getNamedItemNS(DOMString? namespace, DOMString localName);
   [CEReactions] Attr? setNamedItem(Attr attr);
   [CEReactions] Attr? setNamedItemNS(Attr attr);
   [CEReactions] Attr removeNamedItem(DOMString qualifiedName);
   [CEReactions] Attr removeNamedItemNS(DOMString? namespace, DOMString localName);
};

NamedNodeMap имеет связанный «элемент» (element) (элемент).

«Список атрибутов» (attribute list) объекта NamedNodeMap — это список атрибутов его элемента.

 

Поддерживаемые индексы свойств объекта NamedNodeMap — это числа в диапазоне от нуля до размера его списка атрибутов минус один, если только список атрибутов не пуст, и в этом случае индексы поддерживаемых свойств отсутствуют.

Получатель атрибута length должен возвращать размер списка атрибутов.

При вызове метода item(index) необходимо выполнить следующие шаги:

1. Если index равен или больше размера списка атрибутов этого this, возвращается значение null.
2. В противном случае верните список атрибутов[index] этого this.

Имена поддерживаемых свойств объекта NamedNodeMap являются возвращаемым значением при выполнении следующих шагов:

1. Пусть имена names будут полными именами атрибутов в списке атрибутов этого объекта NamedNodeMap, с опущенными дубликатами, по порядку.
2. Если элемент этого объекта NamedNodeMap находится в пространстве имен HTML, а его узловой документ является документом HTML, то для каждого name в names:
   1. Пусть lowercaseName будет именем name в нижнем регистре ASCII.
   2. Если lowercaseName не равен name, удалите name из names.
3. Верните names

Метод getNamedItem(qualifiedName) при вызове должен возвращать результат получения атрибута с заданным qualifiedName и элементом.

Метод getNamedItemNS(namespace, localName) при вызове должен возвращать результат получения атрибута с заданным пространством имен namespace, localName и элементом.

Методы setNamedItem(attr) и setNamedItemNS(attr) при вызове должны возвращать результат установки атрибута, заданного attr и element.

При вызове метода removeNamedItem(qualifiedName) необходимо выполнить следующие действия:

1. Пусть attr будет результатом удаления атрибута с указанным qualifiedName и элемента.
2. Если attr имеет значение null, генерируется исключение DOMException "NotFoundError".
3. Верните attr

Метод removeNamedItemNS(namespace, localName) при вызове должен выполнить следующие действия:

1. Пусть attr будет результатом удаления атрибута с учетом пространства имен namespace, localName и элемента.
2. Если attr имеет значение null, генерируется исключение DOMException "NotFoundError".
3. Верните attr

 

4.9.2 Интерфейс Attr (Атрибут)

IDL

[Exposed=Window]
interface Attr : Node {
   readonly attribute DOMString? namespaceURI;
   readonly attribute DOMString? prefix;
   readonly attribute DOMString localName;
   readonly attribute DOMString name;
   [CEReactions] attribute DOMString value;

   readonly attribute Element? ownerElement;

   readonly attribute boolean specified; // бесполезный; всегда возвращает истину
};

Узлы Attr известны просто как «атрибуты» (attributes). Иногда их называют атрибутами содержимого (content attributes), чтобы избежать путаницы с атрибутами IDL.

Атрибуты имеют «пространство имен» (namespace) (пустая или непустая строка), «префикс пространства имен» (namespace prefix) (пустая или непустая строка), «локальное имя» (local name) (непустая строка), «значение» (value) (строка) и «элемент» (element) (null или элемент).

Примечание!

Если бы они были созданы сегодня, у них было бы просто имя и ценность. ☹

«Полное имя» (qualified name) атрибута — это его локальное имя, если его префикс пространства имен равен null, и его префикс пространства имен, за которым следует двоеточие «:», за которым следует его локальное имя, в противном случае.

Примечание!

Пользовательские агенты могут использовать это как внутренний слот для оптимизации.

Когда создаётся атрибут, ему дается его локальное имя. Если явно не указано при создании атрибута, его пространство имен, префикс пространства имен и элемент устанавливаются равными null, а его значение устанавливается в пустую строку.

«Атрибут A» (A attribute) — это атрибут, локальное имя которого — A, а пространство имен и префикс пространства именnull.

 

Получатель атрибута namespaceURI должен возвращать пространство имен.

Получатель атрибута prefix должен возвращать префикс пространства имен.

Получатель атрибута localName должен возвращать локальное имя.

Получатель атрибута name должен возвращать полное имя.

Получатель атрибута value должен возвращать значение.

Чтобы «установить существующее значение атрибута» (set an existing attribute value), учитывая атрибут attribute и строковое значение value, выполните следующие действия:

1. Если элемент атрибута attribute равен null, установите для значения атрибута attribute - value.
2. В противном случае измените attribute на value.

Установщик атрибута value должен установить существующее значение атрибута с этим this и заданным значением.

 

Получатель атрибута ownerElement должен возвращать элемент этого this.

 

Получатель атрибута specified должен возвращать значение true.

 

4.10 Интерфейс CharacterData (Символьные данные)

IDL

[Exposed=Window]
interface CharacterData : Node {
   attribute [LegacyNullToEmptyString] DOMString data;
   readonly attribute unsigned long length;
   DOMString substringData(unsigned long offset, unsigned long count);
   undefined appendData(DOMString data);
   undefined insertData(unsigned long offset, DOMString data);
   undefined deleteData(unsigned long offset, unsigned long count);
   undefined replaceData(unsigned long offset, unsigned long count, DOMString data);
};

Примечание!

CharacterData — это абстрактный интерфейс, который не существует как узел. Он используется узлами Text, ProcessingInstruction и Comment.

Каждый узел, наследующий от интерфейса CharacterData, имеет связанную изменяемую строку, которую называют «данные» (data).

Чтобы «заменить данные» (replace data) узла node на смещение offset, счетчик count и данные data, выполните следующие действия:

1. Пусть length будет длиной node.
2. Если смещение offset больше длины length, генерируется исключение DOMException "IndexSizeError".
3. Если смещение offset плюс счетчик count больше, чем длина length, установите count как length минус offset.
4. Поставить в очередь запись мутации "characterData" для узла node с null, null, данными node, «», «», null и null.
5. Вставить data в данные node после смещения offset единиц кода .
6. Пусть смещение удаления delete offset будет offset + длина данных data.
7. Начиная с единиц кода удаления смещения delete offset, удалите единицы кода count из данных node.
8. Для каждого живого диапазона, начальным узлом которого является узел node, а начальное смещение больше смещения offset, но меньше или равно offset плюс count, установите его начальное смещение равным offset.
9. Для каждого живого диапазона, конечный узел которого является узлом node, а конечное смещение больше смещения offset, но меньше или равно offset плюс count, установите его конечное смещение на offset.
10. Для каждого живого диапазона, у которого начальным узлом является узел node, а начальное смещение больше, чем смещение offset плюс count, увеличьте его начальное смещение на длину данных data и уменьшите его на счетчик count.
11. Для каждого живого диапазона, конечным узлом которого является узел node, а конечное смещение больше, чем смещение offset плюс count, увеличьте его конечное смещение на длину данных data и уменьшите его на счетчик count.
12. Если родитель узла node не равен null, выполните шаги изменения детей для родителя узла node.

Чтобы «под-строчить данные» (substring data) с узлом node, смещением offset и счетчиком count, выполните следующие действия:

1. Пусть length будет длиной узла node.
2. Если смещение offset больше длины length, генерируется исключение DOMException "IndexSizeError".
3. Если смещение offset плюс счетчик count больше длины length, вернуть строку, значение которой представляет собой единицы кода от единицы кода смещения offset до конца данных узла node, а затем вернуть.
4. Возвращает строку, значение которой является единицей кода от единицы кода смещения offset до единицы кода смещения offset + счетчика count в данных узла node.

Получатель атрибута data должен возвращать данные этого this. Его установщик должен заменить данные с узлом this, смещение 0, подсчитать длину этого this и новое значение данных.

Получатель атрибута length должен возвращать длину этого this.

Метод substringData(offset, count) при вызове должен возвращать результат выполнения под-строчивания данных с узлом этого this, смещением offset и счётчиком count.

Метод appendData(data) при вызове должен заменять данные с узлом этого this, смещением длины этого this, счетчиком 0 и данными data.

Метод insertData(offset, data) при вызове должен заменить данные с узлом этого this, смещением offset, счетчиком 0 и данными data.

Метод deleteData(offset, count) при вызове должен заменить данные с узлом этого this, смещением offset, счетчиком count и данными пустой строки.

Метод replaceData(offset, count, data) при вызове должен заменить данные с узлом этого this, смещением offset, счетчиком count и данными data.

 

4.11 Интерфейс Text (Текст)

IDL

[Exposed=Window]
interface Text : CharacterData {
   constructor(optional DOMString data = "");

   [NewObject] Text splitText(unsigned long offset);
   readonly attribute DOMString wholeText;
};

Для веб-разработчиков (не нормативно)

text = new Text([data = «»])

Возвращает новый текстовый узел Text, данные которого являются data.

text . splitText(offset)

Разделяет данные по заданному смещению offset и возвращает остаток как текстовый узел Text.

text . wholeText

Возвращает объединенные данные всех прямых братьев и сестер (родственников) текстового узла Text.

 

«Эксклюзивный узел Text»  (exclusive Text node) — это текстовый узел Text, который не является узлом CDATASection.

«Смежными узлами Text» (contiguous Text nodes) узла node являются node, узел Text предыдущего родственника node, если он есть, и его смежные узлы Text, и узел Text следующего родственника node, если есть, и его смежные узлы Text, избегая любых дубликатов.

«Смежные эксклюзивные узлы Text» (contiguous exclusive Text nodes) узла node — это node, предыдущего родственника эксклюзивный узел Text node, если таковой имеется, и его смежные эксклюзивные узлы Text, и следующий родственник эксклюзивный узел Text, если таковой имеется, и его смежные эксклюзивные узлы Text, избегая любых дубликатов.

«Текстовое содержимое ребёнка» (child text content) узла node — это объединение данных всех детей узла Text из node в древовидном порядке.

«Текстовое содержимое потомка» (descendant text content) узла node — это объединение данных всех потомков узла Text из node в древовидном порядке.

 

Конструктор Text(data) при вызове должен возвращать новый узел Text, данные которого являются data, а документ узла — это связанный Document текущего глобального объекта.

Чтобы «разделить» (split) узел Text node со смещением offset, выполните следующие действия:

1. Пусть length будет длиной узла node.
2. Если смещение offset больше длины length, генерируется исключение DOMException "IndexSizeError".
3. Пусть count будет length минус offset.
4. Пусть новые данные new data будут результатом подстроки данных с узлом node, смещением offset и счетчиком count.
5. Пусть новый узел new node будет новым узлом Text с тем же документом узла, что и node. Установите данные new node на new data.
6. Пусть parent будет родителем узла node.
7. Если parent не равен null, тогда:
   1. Вставить новый узел new node в parent до следующего родственника узла node.
   2. Для каждого живого диапазона, чей начальный узел является node, а начальное смещение больше offset, установите его начальный узел на new node и уменьшите его начальное смещение на offset.
   3. Для каждого активного диапазона, конечным узлом которого является node, а конечное смещение больше offset, установите его конечный узел на new node и уменьшите его конечное смещение на offset.
   4. Для каждого живого диапазона, начальный узел которого является parent, а начальное смещение равно индексу node плюс 1, увеличьте его начальное смещение на 1.
   5. Для каждого живого диапазона, конечный узел которого является parent, а конечное смещение равно индексу node плюс 1, увеличьте его конечное смещение на 1.
8. Замените данные с узлом node, смещением offset, счетчиком count и данными пустой строкой.
9. Верните new node.

Метод splitText(offset) при вызове должен разделить этого this со смещением offset.

Получатель атрибута wholeText должен возвращать конкатенацию данных смежных узлов Text этого this в древовидном порядке.

 

4.12 Интерфейс CDATASection (Раздел CDATA)

IDL

[Exposed=Window]
interface CDATASection : Text {
};

 

4.13 Интерфейс ProcessingInstruction (Инструкция по обработке)

IDL

[Exposed=Window]
interface ProcessingInstruction : CharacterData {
readonly attribute DOMString target;
};

Узлы ProcessingInstruction имеют связанную «цель» (target).

Атрибут target должен возвращать цель.

 

4.14 Интерфейс Comment (Комментарий)

IDL

[Exposed=Window]
interface Comment : CharacterData {
constructor(optional DOMString data = "");
};

Для веб-разработчиков (не нормативно)

comment = new Comment([data = «»])

Возвращает новый узел комментария Comment, данные которого являются data.

При вызове конструктора Comment(data) он должен возвращать новый узел Comment, данные которого являются data, а документ узла — это связанный Document текущего глобального объекта.

 

5 Диапазоны

5.1 Введение в «Диапазоны DOM»

Объекты (диапазоны) StaticRange и Range представляют последовательность содержимого в дереве узлов. У каждого диапазона есть начало и конец, которые являются граничными точками. Граничная точка — это кортеж, состоящий из узла и смещения. Другими словами, диапазон представляет собой часть содержимого в дереве узлов между двумя граничными точками.

Диапазоны часто используются при редактировании для выбора и копирования содержимого.

Element: p
   Element: <img src="insanity-wolf" alt="Little-endian BOM; decode as big-endian!">
   Text: CSS 2.1 syndata is
   Element: <em>
      Text: awesome
   Text: !

В приведенном выше дереве узлов диапазон может использоваться для представления последовательности «Syndata is awes». Предполагая, что p назначен элементу p, а em элементу em, это будет сделано следующим образом:

var range = new Range(),
   firstText = p.childNodes[1],
   secondText = em.firstChild
range.setStart(firstText, 9) // не забываем начальный пробел
range.setEnd(secondText, 4)
// теперь диапазон преобразуется в указанную выше цитату

Примечание!

Такие атрибуты, как src и alt в дереве узлов выше не могут быть представлены диапазоном. Диапазоны полезны только для узлов.

На объекты диапазона Range, в отличие от объектов StaticRange, влияют изменения в дереве узлов. Поэтому они также известны как живые диапазоны. Такие мутации не сделают их недействительными и будут пытаться гарантировать, что он по-прежнему представляет тот же фрагмент контента. Обязательно, живой диапазон сам может быть изменен как часть мутации дерева узлов, когда, например, мутирует часть содержимого, которое он представляет.

Примечание!

Смотри подробности в алгоритмах вставки и удаления, методе normalize(), а также в алгоритмах замены данных и разделения.

Обновление динамических диапазонов в ответ на мутации дерева узлов может быть дорогостоящим. При каждом изменении дерева узлов необходимо обновить все затронутые объекты Range. Даже если приложение не интересуется некоторыми живыми диапазонами, оно все равно должно оплачивать их актуальность при возникновении мутации.

Объект StaticRange — это облегченный диапазон, который не обновляется при мутации дерева узлов. Следовательно, на него не взимаются такие же расходы на техническое обслуживание, как на живые диапазоны.

 

5.2 Граничные точки

«Граничная точка» (boundary point) — это кортеж, состоящий из «узла» (node) (узла) и «смещения» (offset) (неотрицательного целого числа).

Примечание!

Правильное смещение граничной точки будет между 0 и длиной узла граничной точки включительно.

«Позиция» (position) граничной точки (nodeA, offsetA) относительно граничной точки (nodeB, offsetB) «до» (before), «равно» (equal) или «после» (after), как возвращается на следующих этапах:

1. Утверждение: nodeA и nodeB имеют один и тот же корень.
2. Если nodeA является nodeB, тогда возвращается равное значение, если offsetA равно offsetB, до, если offsetA меньше, чем offsetB, и после, если offsetA больше, чем offsetB.
3. Если nodeA следует за nodeB, то, если позиция (nodeB, offsetB) относительно (nodeA, offsetA) находится до, вернуть после, а если это является после, вернуть до.
4. Если nodeA является предком nodeB:
   1. Пусть child будет nodeB.
   2. Пока child не является ребёнком по отношению к nodeA, установите child для своего родителя.
   3. Если индекс child меньше offsetA, верните после.
5. Верните до

 

5.3 Интерфейс AbstractRange (Абстрактный диапазон)

IDL

[Exposed=Window]
interface AbstractRange {
   readonly attribute Node startContainer;
   readonly attribute unsigned long startOffset;
   readonly attribute Node endContainer;
   readonly attribute unsigned long endOffset;
   readonly attribute boolean collapsed;
};

Объекты, реализующие интерфейс AbstractRange, известны как «диапазоны» (ranges).

У диапазона есть две связанные граничные точки — «начало» (start) и «конец» (end).

Для удобства «начальный узел» (start node) диапазона — это его узел начала, его «начальное смещение» (start offset) — это его смещение начала, его «конечный узел» (end node) — его узел конца, а его «конечное смещение» (end offset) — это его смещение конца.

Диапазон «сворачивается» (collapsed), если его начальный узел является его конечным узлом, а его начальное смещение является его конечным смещением.

Для веб-разработчиков (не нормативно)

node = range . startContainer

Возвращает начальный узел диапазона range.

offset = range . startOffset

Возвращает начальное смещение диапазона range.

node = range . endContainer

Возвращает конечный узел диапазона range.

offset = range . endOffset

Возвращает конечное смещение диапазона range.

collapsed = range . collapsed

Возвращает true, если диапазон range свернут, и false в противном случае.

Получатель атрибута startContainer должен возвращать начальный узел этого this.

Получатель атрибута startOffset должен возвращать начальное смещение этого this.

Получатель атрибута endContainer должен возвращать конечный узел этого this.

Получатель атрибута endOffset должен возвращать конечное смещение этого this.

Получатель атрибута collapsed должен возвращать true, если он свернут, и false в противном случае.

 

5.4 Интерфейс StaticRange (Статический диапазон)

IDL

dictionary StaticRangeInit {
   required Node startContainer;
   required unsigned long startOffset;
   required Node endContainer;
   required unsigned long endOffset;
};

[Exposed=Window]
interface StaticRange : AbstractRange {
   constructor(StaticRangeInit init);
};

Для веб-разработчиков (не нормативно)

staticRange = new StaticRange(init)

Возвращает новый объект диапазона, который не обновляется при мутации дерева узлов.

Конструктор StaticRange(init) при вызове должен выполнить следующие шаги:

1. Если startContainer или endContainer инициализации init является узлом DocumentType или Attr, то генерирует исключение DOMException "InvalidNodeTypeError".
2. Пусть staticRange будет новым объектом StaticRange.
3. Установите для начала staticRange (startContainer init, startOffset init) и конца (endContainer init, endOffset init).
4. Вернуть staticRange

 

5.5 Интерфейс Range (Диапазон)

IDL

[Exposed=Window]
interface Range : AbstractRange {
   constructor();

   readonly attribute Node commonAncestorContainer;

   undefined setStart(Node node, unsigned long offset);
   undefined setEnd(Node node, unsigned long offset);
   undefined setStartBefore(Node node);
   undefined setStartAfter(Node node);
   undefined setEndBefore(Node node);
   undefined setEndAfter(Node node);
   undefined collapse(optional boolean toStart = false);
   undefined selectNode(Node node);
   undefined selectNodeContents(Node node);

   const unsigned short START_TO_START = 0;
   const unsigned short START_TO_END = 1;
   const unsigned short END_TO_END = 2;
   const unsigned short END_TO_START = 3;
   short compareBoundaryPoints(unsigned short how, Range sourceRange);

   [CEReactions] undefined deleteContents();
   [CEReactions, NewObject] DocumentFragment extractContents();
   [CEReactions, NewObject] DocumentFragment cloneContents();
   [CEReactions] undefined insertNode(Node node);
   [CEReactions] undefined surroundContents(Node newParent);

   [NewObject] Range cloneRange();
   undefined detach();

   boolean isPointInRange(Node node, unsigned long offset);
   short comparePoint(Node node, unsigned long offset);

   boolean intersectsNode(Node node);

   stringifier;
};

Объекты, реализующие интерфейс Range, известны как «живые диапазоны» (live ranges).

Примечание!

Алгоритмы, которые изменяют дерево (в частности, алгоритмы вставки, удаления, замены данных и разделения), изменяют живые диапазоны, связанные с этим деревом.

«Корень» (root) живого диапазона — это корень его начального узла.

Узел node «содержится» (contained) в живом диапазоне range, если корень node является корнем range, а (node, 0) находится после начала range, а (node, длина node) находится перед концом range.

Узел «частично содержится» (partially contained) в живом диапазоне, если он является инклюзивным предком начального узла живого диапазона, но не его конечный узел, или наоборот.

Примечание!

Некоторые факты, чтобы лучше понять эти определения:

Контент, который можно было бы считать находящимся в пределах живого диапазона, состоит из всех содержащихся узлов, плюс, возможно, часть содержимого начального узла и конечного узла, если это узлы Text, ProcessingInstruction или Comment.

Узлы, которые содержатся в живом диапазоне, обычно не будут смежными, потому что родитель содержащегося узла не всегда будет содержащимся.

Однако потомки содержащегося узла содержатся, и если два родственника (брата и сестры) содержатся, то же самое и с любыми родственниками, лежащими между ними.

Начальный узел и конечный узел из живого диапазона никогда не содержатся в нём.

Первый содержащийся узел (если есть) всегда будет после начального узла, а последний содержащийся узел всегда будет равен последнему потомку конечного узла или перед ним.

Частично содержащийся узел существует тогда и только тогда, когда начальный узел и конечный узел различны.

Значение атрибута commonAncestorContainer не содержится и не содержится частично.

Если начальный узел является предком конечного узла, общий инклюзивный предок будет начальным узлом. Ровно один из его детей будет содержаться частично, а ребёнок будет содержаться тогда и только тогда, когда он предшествует частично содержащемуся ребёнку. Если конечный узел является предком начального узла, верно обратное.

Если начальный узел не является инклюзивным предком конечного узла, и наоборот, общий инклюзивный предок будет отличаться от них обоих. Ровно два его ребёнка будут частично содержаться, а ребёнок будет содержаться тогда и только тогда, когда он находится между этими двумя.

 

Для веб-разработчиков (не нормативно)

range = new Range()

Возвращает новый живой диапазон.

Конструктор Range() при вызове должен возвращать новый живой диапазон с (связанный Document текущего глобального объекта, 0) в качестве его начала и конца.

 

Для веб-разработчиков (не нормативно)

container = range . commonAncestorContainer

Возвращает узел, наиболее удаленный от документа, который является предком как начального узла range, так и конечного узла диапазона range.

Получатель атрибута commonAncestorContainer должен выполнить следующие шаги:

1. Пусть контейнер container будет начальным узлом.
2. Хотя container не является инклюзивным предком конечного узла, пусть container будет родителем container.
3. Вернуть container

 

Чтобы «установить начало или конец» (set the start or end) диапазона range на граничную точку (node, offset), выполните следующие действия:

1. Если узел node является типом документа, выбросить исключение DOMException "InvalidNodeTypeError".
2. Если смещение offset больше длины узла node, генерируется исключение DOMException "IndexSizeError".
3. Пусть bp будет граничной точкой (node, offset).
4.

   Если эти шаги были вызваны как «установить начало»

      1. Если bp находится после конца диапазона range или если корень range не равен корню node, установите конец range на bp.
      2. Установите начало диапазона range на bp.

   Если эти шаги были вызваны как «установить конец»

      1. Если bp находится перед началом диапазона range или если корень диапазона range не равен корню узла node, установите для начала диапазона range значение bp.
      2. Установите конец диапазона range на bp.

 

Метод setStart(node, offset) при вызове должен установить начало этого this в граничную точку (node, offset).

Метод setEnd(node, offset) при вызове должен установить конец этого this в граничную точку (node, offset).

Метод setStartBefore(node) — (установка начала до) — при вызове должен выполнить следующие шаги:

1. Пусть parent будет родителем узла node.
2. Если родитель parent имеет значение NULL, выбросить исключение DOMException «InvalidNodeTypeError».
3. Установите начало этого this на граничную точку (parent, индекс узла node).

Метод setStartAfter(node) — (установка начала после) — при вызове должен выполнить следующие шаги:

1. Пусть parent будет родителем узла node.
2. Если parent имеет значение NULL, выбросить исключение DOMException «InvalidNodeTypeError».
3. Установите начало этого this на граничную точку (parent, индекс узла node плюс 1).

Метод setEndBefore(node) — (установка конца до) — при вызове должен выполнить следующие шаги:

1. Пусть parent будет родителем узла node.
2. Если parent имеет значение NULL, выбросить исключение DOMException «InvalidNodeTypeError».
3. Установите конец этого this на граничную точку (parent, индекс узла node).

Метода setEndAfter(node) — (установка конца после) — при вызове должен выполнить следующие шаги:

1. Пусть parent будет родителем узла node.
2. Если parent имеет значение NULL, выбросить исключение DOMException «InvalidNodeTypeError».
3. Установите конец этого this на граничную точку (parent, индекс узла node плюс 1).

Метод collapse(toStart) при вызове должен, если toStart имеет значение true, установить конец на начало и в противном случае установить начало на конец.

Чтобы «выбрать» (select) узел node в диапазоне range, выполните следующие действия:

1. Пусть parent будет родителем узла node.
2. Если parent имеет значение NULL, выбросить исключение DOMException «InvalidNodeTypeError».
3. Пусть index будет индексом узла node.
4. Установить начало диапазона range в граничную точку (parent, index).
5. Установить конец диапазона range в граничную точку (parent, index плюс 1).

Метод selectNode(node) при вызове должен выбрать узел внутри этого.

Метод selectNodeContents(node) при вызове должен выполнить следующие шаги:

1. Если узел node является типом документа, выбросить исключение DOMException «InvalidNodeTypeError».
2. Пусть length будет длиной узла node.
3. Установить начало в граничную точку (node, 0).
4. Установите конец в граничную точку (node, length).

 

При вызове метода compareBoundaryPoints(how, sourceRange) необходимо выполнить следующие действия:

1. Если как how не один из

START_TO_START
START_TO_END
END_TO_END
END_TO_START

затем выбросить исключение DOMException "NotSupportedError".
2. Если корень этого this не совпадает с корнем sourceRange, то бросьте исключение DOMException "WrongDocumentError".
3. Если как how является:

START_TO_START:
   Пусть эта точка this point станет началом этого this. Пусть другая точка other point будет началом sourceRange.
START_TO_END:
   Пусть эта точка this point станет концом этого this. Пусть другая точка other point будет началом sourceRange.
END_TO_END:
   Пусть эта точка this point станет концом этого this. Пусть другая точка other point будет концом sourceRange.
END_TO_START:
   Пусть эта точка this point станет началом этого this. Пусть другая точка other point будет концом sourceRange.
4. Если положение этой точки this point относительно другой точки other point является

   до (before)
      Вернуть −1.
   равно (equal)
      Вернуть 0.
   после (after)
      Вернуть 1.

При вызове метода deleteContents() необходимо выполнить следующие действия:

1. Если этот this свёрнут, то вернитесь.
2. Пусть исходный начальный узел (original start node), исходное начальное смещение (original start offset), исходный конечный узел (original end node) и исходное конечное смещение (original end offset) будут начальным узлом этого this, его начальным смещением, конечным узлом и конечным смещением соответственно.
3. Если исходный начальный узел (original start node) и исходный конечный узел (original end node) одинаковы, и они являются узлами Text, ProcessingInstruction или Comment, замените данные узлом original start node, смещением original start offset, счётчиком original end offset минус original start offset и данные пустая строка, а затем вернуться.
4. Пусть удаляемые узлы (nodes to remove) будут списком всех узлов, которые содержатся в этом this, в древовидном порядке, исключая любой узел, чей родитель также содержится в этом this.
5. Если исходный начальный узел (original start node) является инклюзивным предком исходного конечного узла (original end node), установите новый узел (new node) как исходный начальный узел (original start node), а новое смещение (new offset) - как исходное начальное смещение (original start offset).
6. В противном случае
   1. Пусть ссылочный узел (reference node) равен исходному начальному узлу (original start node).
   2. До тех пор пока родитель ссылочного узла (reference node) не является null и не является инклюзивным предком исходного конечного узла (original end node), установите ссылочный узел (reference node) на его родителя.
   3. Установите новый узел (new node) в качестве родителя ссылочного узла (reference node), а новое смещение (new offset) равным единице плюс индекс ссылочного узла (reference node).

Примечание!

Если бы родитель ссылочного узла (reference node) был null, он был бы корнем этого this, то есть был бы инклюзивным предком исходного конечного узла (original end node), и мы не смогли бы достичь этой точки.

7. Если исходный начальный узел (original start node) является узлом Text, ProcessingInstruction или Comment, замените данные с узлом original start node, смещением original start offset, счётчиком original start node минус original start offset, данные пустую строку.
8. Для каждого узла node в удаляемых узлах (nodes to remove) в порядке дерева удалите узел node.
9. Если исходный конечный узел (original end node) является узлом Text, ProcessingInstruction или Comment, замените данные с узлом original end node, смещением 0, счётчиком исходное конечное смещение (original end offset) и данные пустую строку.
10. Установите начало и конец в (new node, new offset).

 

Чтобы «извлечь» (extract) живой диапазон range, выполните следующие действия:

1. Пусть fragment будет новым узлом DocumentFragment, документ узла которого является документом узла начального узла диапазона range.
2. Если диапазон range свернут, вернуть fragment.
3. Пусть исходный начальный узел (original start node), исходное начальное смещение (original start offset), исходный конечный узел (original end node) и исходное конечное смещение (original end offset) будут соответственно начальным узлом, начальным смещением, конечным узлом и конечным смещением диапазона range.
4. Если исходный начальный узел (original start node) является исходным конечным узлом (original end node), и они являются узлами Text, ProcessingInstruction или Comment:
   1. Пусть clone будет клоном исходного начального узла (original start node).
   2. Задайте для данных clone результат подстроки данных с узлом original start node, смещения original start offset и счётчика original end offset минус original start offset.
   3. Добавить клон clone во фрагмент fragment.
   4. Замените данные с узлом original start node, смещением original start offset, счётчиком original end offset минус original start offset и данными пустую строку.
   5. Вернуть fragment
5. Пусть общий предок (common ancestor) будет исходным начальным узлом (original start node).
6. Хотя общий предок (common ancestor) не является инклюзивным предком исходного конечного узла (original end node), установите общего предка (common ancestor) для его собственного родителя.
7. Пусть первый частично содержащий ребёнок (first partially contained child) будет null.
8. Если исходный начальный узел (original start node) не not является инклюзивным предком исходного конечного узла (original end node), установите first partially contained child на первого ребёнка общего предка (common ancestor), который частично содержится в диапазоне range.
9. Пусть последний частично содержащийся ребёнок (last partially contained child) будет null.
10. Если исходный конечный узел (original end node) не not является инклюзивным предком исходного начального узла (original start node), установите last partially contained child на последнего ребёнка общего предка (common ancestor), который частично содержится в диапазоне range.

Примечание!

Эти присвоения переменных действительно всегда имеют смысл. Например, если исходный начальный узел (original start node) не является инклюзивным предком исходного конечного узла (original end node), исходный начальный узел (original start node) сам частично содержится в диапазоне range, как и все его предки до ребёнка общего предка (common ancestor). Общий предок (common ancestor) не может быть исходным начальным узлом (original start node), потому что он должен быть инклюзивным предком исходного конечного узла (original end node). Другой случай аналогичен. Также обратите внимание, что два ребёнка никогда не будут равны, если оба определены.

11. Пусть содержащие дети (contained children) будут списком всех детей общего предка (common ancestor), которые содержатся в диапазоне range, в древовидном порядке.
12. Если какой-либо член содержащихся детей (contained children) является типом документа, выбросить исключение DOMException «HierarchyRequestError».

Примечание!

Нам не нужно беспокоиться о первом или последнем частично содержащемся узле, потому что тип документа никогда не может частично содержаться. Он не может быть граничной точкой диапазона и не может быть предком чего-либо.

13. Если исходный начальный узел (original start node) является инклюзивным предком исходного конечного узла (original end node), установите новый узел (new node) как исходный начальный узел (original start node), а новое смещение (new offset) - как исходное начальное смещение (original start offset).
14. В противном случае
   1. Пусть ссылочный узел (reference node) равен исходному начальному узлу (original start node).
   2. Хотя родитель ссылочного узла (reference node) не равен null и не является инклюзивным предком исходного конечного узла (original end node), установите ссылочный узел (reference node) на его родителя.
   3. Установите новый узел (new node) как родитель для ссылочного узла (reference node), а новое смещение (new offset) равным единице плюс индекс ссылочного узла (reference node).

Примечание!

Если родитель ссылочного узла (reference node) равен null, он будет корнем диапазона range, поэтому будет инклюзивным предком исходного конечного узла (original end node), и мы не сможем достичь этой точки.

15. Если первый частично содержащийся ребёнок (first partially contained child) является узлом Text, ProcessingInstruction или Comment:

Примечание!

В этом случае first partially contained child является original start node.

   1. Пусть clone будет клоном исходного начального узла (original start node).
   2. Установите для данных clone результат подстроки данных с узлом original start node, смещения original start offset и счётчика длины original start node минус original start offset.
   3. Добавить клон clone во фрагмент fragment.
   4. Замените данные узлом original start node, смещением original start offset, подсчитайте длину original start node минус original start offset и данные пустую строку.
16. В противном случае, если первый частично содержащийся ребёнок (first partially contained child) не равен null:
   1. Пусть clone будет клоном первого частично содержащегося ребёнка (first partially contained child).
   2. Добавить клон clone во фрагмент fragment.
   3. Пусть subrange будет новым живым диапазоном, начало которого равно (исходный начальный узел, исходное начальное смещение), а концом (first partially contained child, длина first partially contained child).
   4. Пусть субфрагмент subfragment будет результатом извлечения субдиапазона subrange.
   5. Добавить субфрагмент subfragment в клон clone.
17. Для каждого содержащегося ребёнка (contained child) в содержащихся детях (contained children) добавьте contained child к fragment.
18. Если последним частично содержащимся ребёнком (last partially contained child) является узел Text, ProcessingInstruction или Comment:

Примечание!

В этом случае last partially contained child является original end node.

   1. Пусть clone будет клоном исходного конечного узла (original end node).
   2. Задайте для данных clone результат подстроки данных с узлом original end node, смещением 0 и счётчиком original end offset.
   3. Добавить клон clone во фрагмент fragment.
   4. Замените данные с узлом original end node, смещением 0, счётчиком original end offset и данные пустую строку.
19. В противном случае, если последний частично содержащийся ребёнок (last partially contained child) не равен null:
   1. Пусть clone будет клоном последнего частично содержащегося ребёнка (last partially contained child).
   2. Добавить клон clone во фрагмент fragment.
   3. Пусть subrange будет новым живым диапазоном, начало которого (последний частично содержащий ребёнок, 0), а конец (исходный конечный узел, исходное конечное смещение).
   4. Пусть субфрагмент subfragment будет результатом извлечения субдиапазона subrange.
   5. Добавить субфрагмент subfragment в клон clone.
20. Установите начало и конец диапазона range на (new node, new offset).
21. Вернуть fragment

 

Метод extractContents() при вызове должен вернуть результат извлечения этого this.

 

Чтобы «клонировать содержимое» (clone the contents) живого диапазона range, выполните следующие действия:

1. Пусть fragment будет новым узлом DocumentFragment, документ узла которого является документом узла начального узла диапазона range.
2. Если диапазон range свернут, вернуть fragment.
3. Пусть исходный начальный узел (original start node), исходное начальное смещение (original start offset), исходный конечный узел (original end node) и исходное конечное смещение (original end offset) будут соответственно начальным узлом, начальным смещением, конечным узлом и конечным смещением диапазона range.
4. Если исходный начальный узел (original start node) является исходным конечным узлом (original end node), и они являются узлами Text, ProcessingInstruction или Comment:
   1. Пусть clone будет клоном исходного начального узла (original start node).
   2. Задайте для данных clone результат подстроки данных с узлом original start node, смещения original start offset и счётчика original end offset минус original start offset.
   3. Добавить клон clone во фрагмент fragment.
   4. Вернуть fragment
5. Пусть общий предок (common ancestor) будет исходным начальным узлом (original start node).
6. Хотя общий предок (common ancestor) не является инклюзивным предком исходного конечного узла (original end node), установите общего предка (common ancestor) для его собственного родителя.
7. Пусть первый частично содержащий ребёнок (first partially contained child) будет null.
8. Если исходный начальный узел (original start node) не not является инклюзивным предком исходного конечного узла (original end node), установите first partially contained child на первого ребёнка общего предка (common ancestor), который частично содержится в диапазоне range.
9. Пусть последний частично содержащийся ребёнок (last partially contained child) будет null.
10. Если исходный конечный узел (original end node) не not является инклюзивным предком исходного начального узла (original start node), установите last partially contained child на последнего ребёнка общего предка (common ancestor), который частично содержится в диапазоне range.

Примечание!

Эти присвоения переменных действительно всегда имеют смысл. Например, если исходный начальный узел (original start node) не является инклюзивным предком исходного конечного узла (original end node), исходный начальный узел (original start node) сам частично содержится в диапазоне range, как и все его предки до ребёнка общего предка (common ancestor). Общий предок (common ancestor) не может быть исходным начальным узлом (original start node), потому что он должен быть инклюзивным предком исходного конечного узла (original end node). Другой случай аналогичен. Также обратите внимание, что два ребёнка никогда не будут равны, если оба определены.

11. Пусть содержащие дети (contained children) будут списком всех детей общего предка (common ancestor), которые содержатся в диапазоне range, в древовидном порядке.
12. Если какой-либо член содержащихся детей (contained children) является типом документа, выбросить исключение DOMException «HierarchyRequestError».

Примечание!

Нам не нужно беспокоиться о первом или последнем частично содержащемся узле, потому что тип документа никогда не может частично содержаться. Он не может быть граничной точкой диапазона и не может быть предком чего-либо.

13. Если первый частично содержащийся ребёнок (first partially contained child) является узлом Text, ProcessingInstruction или Comment:

Примечание!

В этом случае first partially contained child является original start node.

   1. Пусть clone будет клоном исходного начального узла (original start node).
   2. Установите для данных clone результат подстроки данных с узлом original start node, смещения original start offset и счётчика длины original start node минус original start offset.
   3. Добавить клон clone во фрагмент fragment.
14. В противном случае, если первый частично содержащийся ребёнок (first partially contained child) не равен null:
   1. Пусть clone будет клоном первого частично содержащегося ребёнка (first partially contained child).
   2. Добавить клон clone во фрагмент fragment.
   3. Пусть subrange будет новым живым диапазоном, начало которого равно (исходный начальный узел, исходное начальное смещение), а концом (first partially contained child, длина first partially contained child).
   4. Пусть подфрагмент subfragment будет результатом клонирования содержимого поддиапазона subrange.
   5. Добавить субфрагмент subfragment в клон clone.
15. Для каждого содержащегося ребёнка (contained child) в содержащихся детях (contained children):
   1. Пусть clone будет клоном содержащегося ребёнка (contained child) с установленным флагом clone children flag.
   2. Добавить клон clone во фрагмент fragment.
16. Если последним частично содержащимся ребёнком (last partially contained child) является узел Text, ProcessingInstruction или Comment:

Примечание!

В этом случае last partially contained child является original end node.

   1. Пусть clone будет клоном исходного конечного узла (original end node).
   2. Задайте для данных clone результат подстроки данных с узлом original end node, смещением 0 и счётчиком original end offset.
   3. Добавить клон clone во фрагмент fragment.
17. В противном случае, если последний частично содержащийся ребёнок (last partially contained child) не равен null:
   1. Пусть clone будет клоном последнего частично содержащегося ребёнка (last partially contained child).
   2. Добавить клон clone во фрагмент fragment.
   3. Пусть subrange будет новым живым диапазоном, начало которого (последний частично содержащий ребёнок, 0), а конец (исходный конечный узел, исходное конечное смещение).
   4. Пусть подфрагмент subfragment будет результатом клонирования содержимого поддиапазона subrange.
   5. Добавить субфрагмент subfragment в клон clone.
18. Вернуть fragment

 

Метод cloneContents() при вызове должен возвращать результат клонирования содержимого этого this.

 

Чтобы «вставить» (insert) узел node в живой диапазон range, выполните следующие действия:

1. Если начальный узел диапазона range является узлом ProcessingInstruction или Comment, является узлом Text, родитель которого равен null, или является node, тогда выбросить исключение DOMException "HierarchyRequestError".
2. Пусть referenceNode будет null.
3. Если начальным узлом диапазона range является текстовый узел Text, установите referenceNode для этого узла Text.
4. В противном случае установите referenceNode для ребёнка начального узла, индекс которого является начальным смещением, и null, если такого ребёнка нет.
5. Пусть parent будет начальным узлом диапазона range, если referenceNode имеет значение null, и родитель referenceNode в противном случае.
6. Убедитесь, что node соответствует до вставки в parent перед referenceNode.
7. Если начальным узлом диапазона range является узел Text, установите для referenceNode значение результата разделения с смещением начального смещения range.
8. Если node является referenceNode, установите referenceNode на его следующего родственника.
9. Если родитель node не равен null, удалите узел node.
10. Пусть newOffset будет длиной родителя parent, если referenceNode имеет значение null, а в противном случае - индексом referenceNode.
11. Увеличьте newOffset на длину node, если node является узлом DocumentFragment, и один в противном случае.
12. Предварительно вставить узел node в parent перед referenceNode.
13. Если диапазон range свёрнут, установите конец диапазона range равным (parent, newOffset).

Метод insertNode(node) при вызове должен вставить узел node в этого this

Метод surroundContents(newParent) при вызове должен выполнить следующие действия:

1. Если нетекстовый узел (non-Text) частично содержится в этом this, то генерируйте исключение DOMException «InvalidStateError».
2. Если newParent является узлом Document, DocumentType или DocumentFragment, то генерирует исключение DOMException «InvalidNodeTypeError».

Примечание!

По историческим причинам узлы Text, ProcessingInstruction и Comment здесь не проверяются и в конечном итоге выбрасываются в качестве побочного эффекта.

3. Пусть фрагмент fragment будет результатом извлечения этого this.
4. Если у newParent есть дети, замените все на null в newParent.
5. Вставьте newParent в этот this.
6. Добавить fragment в newParent.
7. Выберите newParent в this.

Метод cloneRange() при вызове должен возвращать новый живой диапазон с тем же началом и концом, что и этот this.

Метод detach() при вызове ничего не должен делать. Примечание! Его функциональность (отключение объекта Range) была удалена, но сам метод сохранен для совместимости.

 

Для веб-разработчиков (не нормативно)

position = range . comparePoint(node, offset)

Возвращает -1, если точка находится перед диапазоном, 0, если точка находится в диапазоне, и 1, если точка находится после диапазона.

intersects = range . intersectsNode(node)

Возвращает, пересекает ли диапазон range узел node.

 

При вызове метода isPointInRange(node, offset) необходимо выполнить следующие действия:

1. Если корень узла node отличается от корня этого this, верните false.
2. Если узел node является типом документа, выбросить исключение DOMException "InvalidNodeTypeError".
3. Если смещение offset больше длины узла node, генерируется исключение DOMException "IndexSizeError".
4. Если (node, offset) находится до начала или после конца, вернуть false.
5. Верните истину true.

При вызове метода comparePoint(node, offset) необходимо выполнить следующие действия:

1. Если корень узла node отличается от корня этого this, выбросить исключение DOMException "WrongDocumentError".
2. Если узел node является типом документа, выбросить исключение DOMException "InvalidNodeTypeError".
3. Если смещение offset больше длины узла node, генерируется исключение DOMException "IndexSizeError".
4. Если (node, offset) находится до начала, верните -1.
5. Если (node, offset) находится после конца, верните 1.
6. Вернуть 0.

 

При вызове метода intersectsNode(node) необходимо выполнить следующие шаги:

1. Если корень узла node отличается от корня этого this, верните false.
2. Пусть parent будет родителем узла node.
3. Если parent имеет значение null, верните true.
4. Пусть смещение offset будет индексом узла node.
5. Если (parent, offset) находится перед концом, а (parent, offset плюс 1) находится после начала, вернуть истину true.
6. Вернуть false.

«Режим преобразования в строку» (stringification behavior) должен запускать следующие шаги:

1. Пусть s будет пустой строкой.
2. Если начальный узел этого this является конечным узлом этого this и является узлом Text, то верните подстроку данных этого узла Text, начиная с начального смещения этого this и заканчивая конечным смещением этого this.
3. Если начальным узлом этого this является текстовый узел Text, добавьте подстроку данных этого узла от начального смещения этого this до конца к s.
4. Добавить объединение данных всех текстовых узлов Text, содержащихся в этом this, в древовидном порядке к s.
5. Если конечный узел этого this является текстовым узлом Text, добавьте подстроку данных этого узла от его начала до конечного смещения этого this к s.
6. Вернуть s

Примечание!

Методы createContextualFragment(), getClientRects() и getBoundingClientRect() определены в других спецификациях. [DOM-Parsing] [CSSOM-VIEW]

 

6 Обход (Пересечение)

Объекты NodeIterator и TreeWalker можно использовать для фильтрации и обхода деревьев узлов.

Каждый объект NodeIterator и TreeWalker имеет связанный «активный флаг» (active flag), чтобы избежать рекурсивных вызовов. Он изначально не установлен.

Каждый объект NodeIterator и TreeWalker также имеет связанный «корень» (root) (узел), «что показать» (whatToShow) (битовая маска) и «фильтр» (filter) (обратный вызов).

Чтобы «отфильтровать» (to filter) узел node в обходчике traverser объекта NodeIterator и TreeWalker, выполните следующие действия:

1. Если установлен активный флаг у traverser, то выбросить исключение DOMException "InvalidStateError".
2. Пусть n будет значением атрибута nodeType узла node - 1.
3. Если n-ый бит (где 0 - младший значащий бит) из whatToShow обходчика traverser не установлен, то верните FILTER_SKIP.
4. Если фильтр обходчика traverser равен null, вернуть FILTER_ACCEPT.
5. Установить активный флаг для обходчика traverser.
6. Пусть result будет возвращаемым значением вызова операции пользовательского объекта с фильтром обходчика traverser, «acceptNode» и «node». Если это вызывает исключение, снимите активный флаг с traverser и повторно вызовите исключение.
7. Снимите активный флаг с traverser
8. Верните result

 

6.1 Интерфейс NodeIterator (Итератор узла)

IDL

[Exposed=Window]
interface NodeIterator {
   [SameObject] readonly attribute Node root;
   readonly attribute Node referenceNode;
   readonly attribute boolean pointerBeforeReferenceNode;
   readonly attribute unsigned long whatToShow;
   readonly attribute NodeFilter? filter;

   Node? nextNode();
   Node? previousNode();

   undefined detach();
};

 

Примечание!

Объекты NodeIterator могут быть созданы с помощью метода createNodeIterator() для объектов Document.

Каждый объект NodeIterator имеет связанную «коллекцию итераторов» (iterator collection), которая является коллекцией в корне объекта NodeIterator, чей фильтр соответствует любому узлу.

Каждый объект NodeIterator также имеет связанную «ссылку» (reference) (узел) и «указатель перед ссылкой» (pointer before reference) (логическое значение).

Примечание!

Как упоминалось ранее, у объектов NodeIterator есть связанный активный флаг, корень, whatToShow и фильтр.

«Шаги предварительного удаления» (pre-removing steps) NodeIterator, заданные для nodeIterator и toBeRemovedNode, следующие:

1. Если toBeRemovedNode не является инклюзивным предком ссылки nodeIterator или toBeRemovedNode является корнем nodeIterator, тогда вернитесь.
2. Если nodeIterator указатель перед ссылкой истинен, то:
   1. Пусть next будет первым последующим узлом toBeRemovedNode, который является инклюзивным потомком корня nodeIterator и не является инклюзивным потомком toBeRemovedNode, и null, если такого узла нет.
   2. Если next не равно null, то установите ссылку nodeIterator на next и вернитесь.
   3. В противном случае установите указатель перед ссылкой nodeIterator на false.

Примечание!

Шаги здесь не заканчиваются.

3. Установите ссылку nodeIterator на родителя toBeRemovedNode, если предыдущий родственник toBeRemovedNode равен null, и инклюзивный потомок из предыдущего родственника toBeRemovedNode, который в противном случае появляется последним в порядке дерева.

Получатель атрибута root при вызове должен возвращать корень этого this.

Получатель атрибута referenceNode при вызове должен возвращать ссылку этого this.

Получатель атрибута pointerBeforeReferenceNode при вызове должен возвращать указатель перед ссылкой этого this.

Получатель атрибута whatToShow при вызове должен возвращать whatToShow этого this.

Получатель атрибута filter при вызове должен возвращать фильтр этого this.

Чтобы «обойти» (to traverse), учитывая итератор iterator объекта NodeIterator и направление direction, выполните следующие действия:

1. Пусть node будет ссылкой на iterator.
2. Пусть beforeNode будет указателем перед ссылкой итератора iterator.
3. Пока истина:
   1. Ответвление по направлению direction:

   Следующий

      Если beforeNode имеет значение false, тогда установите node на первый узел, следующий за node в коллекции итератора iterator. Если такого узла нет, верните null.
      Если beforeNode истинно true, установите его на ложь false.

   Предыдущий

      Если beforeNode истинно true, тогда установите node на первый узел, предшествующий до node в коллекции итератора iterator. Если такого узла нет, верните null.
      Если beforeNode имеет значение false, установите его в значение true.

   2. Пусть result будет результатом фильтрации узла node в итераторе iterator.
   3. Если result FILTER_ACCEPT, то прервать.
4. Установить ссылку итератора iterator на узел node.
5. Установите указатель перед ссылкой итератора iterator на beforeNode.
6. Вернуть node

Метод nextNode() при вызове должен возвращать результат обхода c this и следующего.

Метод previousNode() при вызове должен возвращать результат обхода с this и предыдущего.

Метод detach() при вызове ничего не должен делать.

Примечание!

Его функциональность (отключение объекта NodeIterator) была удалена, но сам метод сохранен для совместимости.

 

6.2 Интерфейс TreeWalker (Обходчик дерева)

IDL

[Exposed=Window]
interface TreeWalker {
   [SameObject] readonly attribute Node root;
   readonly attribute unsigned long whatToShow;
   readonly attribute NodeFilter? filter;
            attribute Node currentNode;

   Node? parentNode();
   Node? firstChild();
   Node? lastChild();
   Node? previousSibling();
   Node? nextSibling();
   Node? previousNode();
   Node? nextNode();
};

Примечание!

Объекты TreeWalker могут быть созданы с использованием метода createTreeWalker() для объектов Document.

Каждый объект TreeWalker имеет связанный «текущий» (current) (узел).

Примечание!

Как упоминалось ранее, у объектов TreeWalker есть связанный корень, whatToShow и фильтр.

Получатель атрибута root при вызове должен возвращать корень этого this.

Получатель атрибута whatToShow при вызове должен возвращать whatToShow этого this.

Получатель атрибута filter при вызове должен возвращать фильтр этого this.

Получатель атрибута currentNode при вызове должен возвращать текущего этого this.

Установщик атрибута currentNode при вызове должен установить текущего этого this на заданное значение.

 

Метод parentNode() при вызове должен выполнить следующие шаги:

1. Пусть node будет текущим этого this.
2. Пока node не равен null и не является корнем этого this:
1. Установите узел node на родителя node.
2. Если node не равен null и фильтрованный узел node в this возвращает FILTER_ACCEPT, тогда установите текущего этого this для node и верните node.
3. Верните null

Чтобы «обойти детей» (to traverse children) с помощью обходчика walker и типа type, выполните следующие действия:

1. Пусть узел node</