HTMLLabelElement.cpp [plain text]
#include "config.h"
#include "HTMLLabelElement.h"
#include "Document.h"
#include "ElementIterator.h"
#include "Event.h"
#include "EventNames.h"
#include "FormAssociatedElement.h"
#include "HTMLFormControlElement.h"
#include "HTMLNames.h"
#include <wtf/IsoMallocInlines.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLLabelElement);
using namespace HTMLNames;
static LabelableElement* firstElementWithIdIfLabelable(TreeScope& treeScope, const AtomString& id)
{
auto element = makeRefPtr(treeScope.getElementById(id));
if (!is<LabelableElement>(element))
return nullptr;
auto& labelableElement = downcast<LabelableElement>(*element);
return labelableElement.supportLabels() ? &labelableElement : nullptr;
}
inline HTMLLabelElement::HTMLLabelElement(const QualifiedName& tagName, Document& document)
: HTMLElement(tagName, document)
{
ASSERT(hasTagName(labelTag));
}
Ref<HTMLLabelElement> HTMLLabelElement::create(const QualifiedName& tagName, Document& document)
{
return adoptRef(*new HTMLLabelElement(tagName, document));
}
RefPtr<LabelableElement> HTMLLabelElement::control() const
{
auto& controlId = attributeWithoutSynchronization(forAttr);
if (controlId.isNull()) {
for (auto& labelableElement : descendantsOfType<LabelableElement>(*this)) {
if (labelableElement.supportLabels())
return const_cast<LabelableElement*>(&labelableElement);
}
return nullptr;
}
return isConnected() ? firstElementWithIdIfLabelable(treeScope(), controlId) : nullptr;
}
HTMLFormElement* HTMLLabelElement::form() const
{
auto control = this->control();
if (!is<HTMLFormControlElement>(control))
return nullptr;
return downcast<HTMLFormControlElement>(control.get())->form();
}
void HTMLLabelElement::setActive(bool down, bool pause, Style::InvalidationScope invalidationScope)
{
if (down == active())
return;
HTMLElement::setActive(down, pause, invalidationScope);
if (auto element = control())
element->setActive(down, pause);
}
void HTMLLabelElement::setHovered(bool over, Style::InvalidationScope invalidationScope)
{
if (over == hovered())
return;
HTMLElement::setHovered(over, invalidationScope);
if (auto element = control())
element->setHovered(over);
}
bool HTMLLabelElement::isEventTargetedAtInteractiveDescendants(Event& event) const
{
if (!is<Node>(event.target()))
return false;
auto& node = downcast<Node>(*event.target());
if (!containsIncludingShadowDOM(&node))
return false;
for (const auto* it = &node; it && it != this; it = it->parentElementInComposedTree()) {
if (is<HTMLElement>(it) && downcast<HTMLElement>(*it).isInteractiveContent())
return true;
}
return false;
}
void HTMLLabelElement::defaultEventHandler(Event& event)
{
static bool processingClick = false;
if (event.type() == eventNames().clickEvent && !processingClick) {
auto control = this->control();
if (!control || (is<Node>(event.target()) && control->containsIncludingShadowDOM(&downcast<Node>(*event.target())))) {
HTMLElement::defaultEventHandler(event);
return;
}
if (isEventTargetedAtInteractiveDescendants(event)) {
HTMLElement::defaultEventHandler(event);
return;
}
processingClick = true;
control->dispatchSimulatedClick(&event);
document().updateLayoutIgnorePendingStylesheets();
if (control->isMouseFocusable())
control->focus();
processingClick = false;
event.setDefaultHandled();
}
HTMLElement::defaultEventHandler(event);
}
bool HTMLLabelElement::willRespondToMouseClickEvents()
{
auto element = control();
return (element && element->willRespondToMouseClickEvents()) || HTMLElement::willRespondToMouseClickEvents();
}
void HTMLLabelElement::focus(SelectionRestorationMode restorationMode, FocusDirection direction)
{
Ref<HTMLLabelElement> protectedThis(*this);
if (document().haveStylesheetsLoaded()) {
document().updateLayout();
if (isFocusable()) {
Element::focus(restorationMode, direction);
return;
}
}
if (auto element = control())
element->focus(SelectionRestorationMode::RestoreOrSelectAll, direction);
}
bool HTMLLabelElement::accessKeyAction(bool sendMouseEvents)
{
if (auto element = control())
return element->accessKeyAction(sendMouseEvents);
return HTMLElement::accessKeyAction(sendMouseEvents);
}
}