[Перевод] Shadow DOM: спецификация
В каждом алгоритме в этом разделе, Window необходимо рассматривать как если бы это был родительский узел документа — чтобы Window также мог получать события.
Когда событие распределяется в теневое дерево, его путь или проходит по теневым деревьям или заканчивается в теневом корне. Единственное исключение — события изменения (мутации). Такие типы событий никогда не должны распределяться в теневое дерево.
5.1 Всегда останавливаемые события
Следующие события всегда должны быть остановлены в самом младшем теневом корне:
● abort
● error
● select
● change
● load
● reset
● resize
● scroll
● selectstart
Точный алгоритм будет приведен ниже.
5.2 Пути событий
Для определения пути события необходимо использовать алгоритм расчёта пути событий, заключающийся в выполнении следующих действий:
Ввод
УЗЕЛ, узел (node)
СОБЫТИЕ, событие (event)
Вывод
ПУТЬ, путь события, упорядоченный список целей события.
1. ПУТЬ должен быть пустым упорядоченным списком.
2. ТЕКУЩИЙ ЭЛЕМЕНТ должен быть УЗЛОМ
3. Повторять до тех пор пока ТЕКУЩИЙ ЭЛЕМЕНТ существует:
1. Добавить ТОЧКУ ВКЛЮЧЕНИЯ в ПУТЬ
2. Если окончательные точки включения ТЕКУЩЕГО ЭЛЕМЕНТА не являются пустыми:
1. Добавить каждую точку включения в окончательные точки включения ТЕКУЩЕГО ЭЛЕМЕНТА, от первого, включающего, до последнего, исключающего, в ПУТЬ.
2… ТЕКУЩИЙ ЭЛЕМЕНТ должен быть окончательным назначением ТЕКУЩЕГО ЭЛЕМЕНТА
3. Иначе, если все следующие условия соблюдены, остановить этот алгоритм:
1. Если ТЕКУЩИЙ ЭЛЕМЕНТ является теневым корнем:
2. Если ТЕКУЩИЙ ЭЛЕМЕНТ — это корневой узел УЗЛА
3. Установлен scoped flag.
4. Иначе: ТЕКУЩИЙ ЭЛЕМЕНТ должен быть глубоким родителем (deep parent) ТЕКУЩЕГО ЭЛЕМЕНТА.
5.3 Примеры путей событий
Этот раздел является ненормативным
Предположим у нас есть следующее дерево деревьев:
Рис. 5 Пример дерева деревьев. Узлы, которые не участвуют в рассматриваемом пути события, описанном ниже, опущены.
● A это документ.
● E, J, N, Q, S — это теневые корни.
● I, M, P, R и U точки включения содержимого.
Это дерево деревьев состоит из следующих шести деревьев: одного дерева документа и пяти теневых деревьев:
● Дерево документа 1. В него входят узлы A, B, C и D.
● Теневое дерево 2 содержащееся в B. В него входят узлы E, F, G, H и I.
● Теневое дерево 3 содержащееся в H. В него входят узлы J, K, L и M.
● Теневое дерево 4 содержащееся в K. В него входят узлы N, O и P.
● Теневое дерево 5 содержащееся в O. В него входят узлы Q и R.
● Теневое дерево 6 содержащееся в F. В него входят узлы S, T и U.
Давайте предположим, что результат распределения этого дерева деревьев таков:
● Назначения точек включения C это [I, M] (C перераспределена)
● Назначения точек включения L это [P, R] (L перераспределена)
● Назначения точек включения G это [U]
В этом случае, если событие отправляется на узел D, путь события будет следующим:
[D, C, I, M, L, P, R, Q, O, N, K, J, H, G, U, T, S, F, E, B, A] (Без учета Window)
Обратите внимание, что алгоритм расчета пути события разработан для достижения следующих целей:
1. Если в пути события есть узел ПОТОМОК и у него есть РОДИТЕЛЬ в дереве узлов, путь события также будет включать и РОДИТЕЛЯ. РОДИТЕЛЬ всегда появляется где-нибудь после ПОТОМКА в пути события.
2. Узлы в пути события образуют линейную цепочку предков в каждом дереве узлов. Ни в одном дереве узлов нет точек ветвления.
Рис. 6 На этом рисунке цифра в левой части каждого узла отображает начальное положение каждого узла в пути событий. У родительского узла эта цифра всегда больше, чем у любого из его потомков в каждом дереве узлов.
Это говорит о том, что если мы сосредоточимся на одном дереве узлов и забудем обо всех остальных, путь события будет выглядеть так, как если бы событие произошло только в том дереве узлов, о котором идёт речь. Это — важный аспект в том смысле, что наличие теневого дерева никаким образом не влияет на путь события внутри того дерева узлов, в котором содержится ведущий теневой элемент, до тех пор пока событие не будет остановлено в каком-либо из деревьев-потомков.
Например, с точки зрения дерева документа 1, путь события должен выглядеть так: [D, C, B, A]. С точки зрения теневого дерева 2, путь события должен выглядеть как [I, H, G, F, E]. Похожим правилам подчиняются и другие деревья узлов.
Стоит также отметить, что если исключить все точки включения и теневые корни из пути событий, результат был бы эквивалентен содержащим предкам узла в составленном дереве на котором происходит событие.
Рис. 7 Соотношение между путем событий и составленным деревом. Путь события, используемого в примере показан на рисунке слева, а составленное дерево — с правой. Если исключить все точки включения и теневые корни из пути события, результат будет соответствовать содержащим предкам узла D в составленном дереве.
5.4 Перенаправление событий
В тех случаях, когда путь события проходит по нескольким деревьям узлов, информация события о его цели может регулироваться в зависимости от порядка обработки инкапсуляции. Перенаправление событий это процесс вычисления соответствующих целевых элементов для каждого предка узла, в котором происходит событие. Относительный целевой элемент это узел, наиболее точно представляющий целевой элемент события данного предка с сохранением инкапсуляции.
Алгоритм перенаправления должен быть использован для определения относительных целей и заключаться в выполнении следующих шагов:
Ввод
ТЕКУЩИЙ ПУТЬ, путь события
ТЕКУЩАЯ ЦЕЛЬ, узел на котором срабатывает слушатель события.
Вывод
ОТНОСИТЕЛЬНАЯ ЦЕЛЬ, скорректированный целевой элемент
1. ДЕРЕВО ТЕКУЩЕЙ ЦЕЛИ должно быть деревом узлов, в котором содержится ТЕКУЩАЯ ЦЕЛЬ
2. ПЕРВОНАЧАЛЬНАЯ ЦЕЛЬ должна быть первым элементом в ПУТИ СОБЫТИЯ
3. ДЕРЕВО ПЕРВОНАЧАЛЬНОЙ ЦЕЛИ должно быть деревом узлов, в котором содержится ПЕРВОНАЧАЛЬНАЯ ЦЕЛЬ
4. ДЕРЕВО ОТНОСИТЕЛЬНОЙ ЦЕЛИ должно быть ближайшим общим содержащим деревом потомков ДЕРЕВА ТЕКУЩЕЙ ЦЕЛИ и ДЕРЕВА ОТНОСИТЕЛЬНОЙ ЦЕЛИ.
5. ОТНОСИТЕЛЬНЫЙ ЦЕЛЕВОЙ ЭЛЕМЕНТ должен быть первым узлом в ПУТИ СОБЫТИЯ, удовлетворяющим следующим условиям:
1. Узел должен содержаться в ДЕРЕВЕ ОТНОСИТЕЛЬНОГО ЦЕЛЕВОГО ЭЛЕМЕНТА
Процесс перенаправления должен происходить до того, как событие будет доставлено элементу.
5.5 Перенаправление relatedTarget
У некоторых событий есть свойство relatedTarget [DOM-Level-3-Events], которое содержит узел не являющийся целью события, но имеющий к нему отношение.
Например, для события mouseover, relatedTarget может указывать на узел, с которого указатель мыши перешел на текущий элемент. В случае, когда relatedTarget находится в теневом дереве, то соответствующие пользовательские агенты не должны допускать утечек его фактического значения за пределы этого дерева. В тех случаях, когда и relatedTarget и target принадлежат к одному и тому же теневому дереву, то соответствующие пользовательские агенты должны остановить события в теневом корне, чтобы избежать появления побочных mouseover и mouseout событий одновременно из одного узла.
Таким образом, если событие имеет свойство relatedTarget, его значение и элемент который должен ему соответствовать должны быть скорректированы.
Процесс перенаправления relatedTarget должен происходить прежде, чем событие будет доставлено элементу.
5.6 Перенаправление событий прикосновения
Атрибут Touch target [СОБЫТИЯ ПРИКОСНОВЕНИЯ] должен быть скорректирован таким же образом, как событие с relatedTarget. Каждый аттрибут Touch target в списке TouchList, возвращаемый вызовом TouchEvent touches (), changedTouches () и targetTouches () должен быть результатом выполнения алгоритма расчета относительной цели с УЗЛОМ и Touch target в качестве вводных данных.
5.7 Перенаправление событий фокуса
События focus, DOMFocusIn, blur, и DOMFocusOut должны быть обработаны таким же образом, как события с relatedTarget, где потеря узлом фокуса является результатом получения этого фокуса другим узлом или целевым элементом события, что приводит к тому, что узел потерявший фокус становится относительной целью по отношению к узлу его получившему.
5.8 Передача событий
В момент передачи события:
● Атрибуты Event target и currentTarget должны возвращать относительную цель для узла на котором сработали слушатели события
● Атрибут relatedTarget события MouseEvent должен возвращать скорректированную относительную цель
● Атрибуты offsetX и offsetY события MouseEvent должны возвращать значение точки начала координат относительной цели с учётом внутренних отступов.
● Атрибут Touch target должен возвращать скорректированную относительную цель
● Если relatedTarget и target это один и тот же элемент для данного узла, слушатели событий не должны на нем срабатывать. TouchEvent этому правилу не подчиняется.
● Если узел является собственной относительной целью, слушатели событий не должны на нем срабатывать во время фазы захвата, влекущей за собой шаг 6 алгоритма передачи событий.
● Если узел, на котором сработал слушатель события является собственной относительной целью, атрибут eventPhase события должен возвращать значение AT_TARGET во время фазы всплытия, влекущей за собой шаг 9 алгоритма передачи событий.
● Если значение атрибута bubbles события равно false, должно быть выполнено следующее:
1. Путь события должен быть сортирован в обратном порядке
2. Значение атрибута события eventPhase должно быть установлено в AT_TARGET
3. Для каждого объекта в пути события относительная цель которого равна самому объекту, должен быть вызван слушатель события с самим событием в качестве аргумента до тех пор, пока флаг события останавливающий всплытие не будет отключен
После завершения передачи события объекты target и currentTarget события должны указывать на относительную цель наивысшего родителя.
Этот шаг является необходимым для того, чтобы можно было избежать обнаружения узлов в теневом дереве, так как для скрипта представляется возможным передать объект события за пределы его области видимости.
5.9 Пример перенаправления события
Этот раздел является ненормативным.
Предположим, у нас есть интерфейс пользователя, медиаконтроллер, составленный из дерева документа и теневых деревьев. В этом примере мы также предположим, что селекторы способны пересекать границы теневого дерева и попытаемся использовать эти селекторы для того, чтобы идентифицировать элементы. Также мы изобретем вымышленный элемент теневого корня чтобы разделить теневые границы и представить теневые корни:
ПРИМЕР 1
Допустим, пользователь располагает своё указывающее устройство над линейным переключателем громкости (#volume-slider-thumb), это вызывает событие mouseover на этом узле. Давайте также представим что для этого события не существует relatedTarget.
Согласно алгоритму перенаправления, получим следующие значения родительских элементов и относительных целей:
Родитель (Ancestor) Относительная Цель (Relative Target)
После доставки события mouseover с этими новыми относительными целями, пользователь решает поместить указатель над фейдером регулятора громкости (#timeline-slider-thumb). Это вызовет событие mouseout на переключателе шкалы громкости и mouseover на фейдере.
Давайте посмотрим, как это повлияет на значение relatedTarget события mouseout фейдера. Для этого события, relatedTarget это и есть фейдер (#timeline-slider-thumb). Согласно алгоритму расчета относительной цели, мы должны получить следующие значения для родительских элементов, относительных и скорректированных относительных целей:
Родитель (Ancestor) Относительная Цель (Relative Target) Скорректированная относительная Цель (Adjusted related Target)
Узел, #player, имеет свойства target и relatedTarget указывающие на одинаковое значение (#player), что говорит о том, что мы не передали событие этому узлу и его предкам.